Pilotage de mes volets sous Tuya

Bonjour,

Ce matin je souhaitais vous partager mon flow sur la gestion des volets sous Tuya avec Node-Red (un de plus vous allez me dire :slight_smile: )

Tout d’abord, je remercie à nouveau la communauté qui m’a permis d’en arriver là.

1. Mes sources d’inspiration

Gestion Automatique des volets sous Node-Red (Azimuth)
Automatiser ses volets roulants en fonction du soleil été / hiver
Enfin:
Gestion des volets sous Node-Red en fonction du soleil, avec offsets paramétrables

2. Introduction

Tout d’abord une explication.
Tuya et HA ne sont pas synchronisé sur leur code d’état retour ce qui à pour conséquence une inversion des commandes lorsque HA pilote un volet Tuya.
En effet, Tuya renvoie 0 pour « volet fermé » là où HA attend 1 et inversement.
Par ailleurs, je me lançait dans Node-Red et je voulais voir mes limites.
De plus, je cherchais à comprendre le fonctionnement de Lovelace (sur ce point pas sûr du tout d’avoir été très loin quand je vois ce que vous faite. :smiling_face_with_tear:)

Je souhaitais me faire une doc pour y revenir plus tard (habitude de travail :slight_smile: ) je me suis dit que la partager serait mieux.

Aller je me lance.

Les fonctions du flow

  • Voici la liste des fonctions actuellement gérées
  • Ouverture/Fermeture/Arrêt manuel du volet
  • Gestion d’Ouverture/Fermeture en fonction de l’heure
  • Gestion d’Ouverture/Fermeture en fonction du soleil avec possibilité de décalage (Offset)
  • Gestion de la position du volet en fonction de l’Elévation et de l’Azimut du soleil dans le ciel

Les entités

Afin de mener à bien ce projet, j’ai dû créer une grande liste d’entité. Je vais vous les donner pour un volet charge à vous de dupliquer à votre convenance.

configuration.yaml

input_number: !include input_number.yaml
input_boolean: !include input_boolean.yaml
input_datetime: !include input_datetime.yaml

J’ai donc créé au même niveau que mon fichier configuration.yaml, les fichiers:

  • input_number.yaml
  • input_boolean.yaml
  • input_datetime.yaml

Leur contenu

  1. input_number.yaml
# Gestion des pourcentages d'ouverture des volets roulants
volets_niveau_bureau:
  name: volets_niveau_bureau
  min: 0
  max: 100
  step: 1
  mode: box
# Décalage d'ouverture volets
volets_auto_offset_ouvre_bureau:
  name: Volets Offset bureau matin
  min: -90
  max: 90
  step: 1
  mode: slider
volets_auto_offset_ferme_bureau:
  name: Offset bureau soir
  min: -90
  max: 90
  step: 1
  mode: slider
  1. input_boolean.yaml
# Entité permettant l'activation ou non d'une fonction
volets_auto_azimut_global:
    name: volets_auto_azimut_global
    icon: mdi:window-shutter
volets_auto_matin_global:
    name: volets_auto_matin_global
    icon: mdi:window-shutter
volets_auto_soir_global:
    name: volets_auto_soir_global
    icon: mdi:window-shutter
volets_auto_offset_matin_global:
    name: volets_auto_offset_matin_global
    icon: mdi:window-shutter
volets_auto_offset_soir_global:
    name: volets_auto_offset_soir_global
    icon: mdi:window-shutter
# Liste des boutons pilotant le mode auto des volets roulants
# Active ou pas la fonction d'ouverture auto du matin
volets_auto_matin_etat_bureau:
    name: volets_auto_matin_etat_bureau
    icon: mdi:window-shutter
# Toggle bascule entre Offset et heure
volets_auto_matin_toggle_bureau:
    name: volets_auto_matin_toggle_bureau
    icon: mdi:window-shutter

# Les mêmes pour le soir
volets_auto_soir_etat_bureau:
    name: volets_auto_soir_etat_bureau
    icon: mdi:window-shutter
volets_auto_soir_toggle_bureau:
    name: volets_auto_soir_toggle_bureau
    icon: mdi:window-shutter

# La gestion de la fonction azimut pour ce volet
volets_auto_azimut_bureau:
    name: volets_auto_azimut_bureau
    icon: mdi:window-shutter
# Liste des actionneurs montants pour volets roulants
volets_up_bureau:
    name: volets_up_bureau
    icon: mdi:arrow-up-bold
    initial: off
# Liste des actionneurs descendants pour volets roulants
volets_down_bureau:
    name: volets_down_bureau
    icon: mdi:arrow-down-bold
    initial: off
# Liste des actionneurs d'arrêt pour volets roulants
volets_stop_bureau:
    name: volets_stop_bureau
    icon: mdi:stop
    initial: off
  1. input_datetime.yaml
#Entités donnant l'heure d'ouverture du volet
volets_auto_time_ouvre_bureau:
  name: volets_auto_time_ouvre_bureau
  has_date: false
  has_time: true
#Entités donnant l'heure de fermeture du volet
volets_auto_time_ferme_bureau:
  name: volets_auto_time_ferme_bureau
  has_date: false
  has_time: true

Vous remarquerez que j’ai normé les noms de variable. Si vous voulez que cela fonctionne vous ne devez modifier que le dernier tronçon du nom ici le nom du lieu « bureau ».

L’integration

Pour la gestion météorologique, j’ai utilisé l’intégration météo France.

L’interface

Pour la créer, j’ai utilisé le button-card de la communauté HACS.

views:
  - title: test
    path: test
    layout:
      width: 350
    type: custom:vertical-layout
    badges: []
    cards:
      - type: horizontal-stack
        cards:
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: false
                show_icon: false
                color_type: blank-card
                styles:
                  card:
                    - height: 30px
                    - width: 50px
              - type: custom:button-card
                show_name: false
                show_icon: false
                color_type: blank-card
                styles:
                  card:
                    - height: 25px
                    - width: 50px
              - type: custom:button-card
                show_name: false
                show_icon: false
                color_type: blank-card
                styles:
                  card:
                    - height: 25px
                    - width: 50px
              - type: custom:button-card
                show_name: false
                show_icon: false
                color_type: blank-card
                styles:
                  card:
                    - height: 25px
                    - width: 50px
              - type: custom:button-card
                show_name: true
                show_icon: false
                styles:
                  card:
                    - height: 25px
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 50px
                  name:
                    - color: rgb(0, 0, 0)
                    - font-weight: bold
                    - position: absolute
                    - left: 20px
                tap_action:
                  action: none
                show_state: false
                name: '%'
                hold_action:
                  action: none
              - type: custom:button-card
                show_name: true
                show_icon: false
                styles:
                  card:
                    - height: 124px
                    - background-color: rgb(255, 253, 179)
                    - width: 50px
                  name:
                    - color: rgb(0, 0, 0)
                    - font-weight: bold
                    - position: absolute
                    - left: 2px
                    - top: 55px
                tap_action:
                  action: none
                show_state: false
                name: Matin
                hold_action:
                  action: none
              - type: custom:button-card
                show_name: true
                show_icon: false
                styles:
                  card:
                    - height: 124px
                    - background-color: rgb(204, 255, 204)
                    - width: 50px
                  name:
                    - color: rgb(0, 0, 0)
                    - font-weight: bold
                    - position: absolute
                    - left: 10px
                    - top: 55px
                tap_action:
                  action: toggle
                show_state: false
                entity: input_boolean.volets_auto_soir_global
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: rgb(38, 128, 199)
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                name: Soir
                hold_action:
                  action: none
              - type: custom:button-card
                show_name: true
                show_icon: false
                styles:
                  card:
                    - height: 25px
                    - background-color: rgb(204, 204, 255)
                    - width: 50px
                  name:
                    - font-weight: bold
                    - position: absolute
                    - left: 5px
                    - top: 5px
                    - font-size: 12px
                tap_action:
                  action: toggle
                show_state: false
                entity: input_boolean.volets_auto_azimut_global
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: rgb(0, 0, 0)
                  - value: 'off'
                    styles:
                      card:
                        - color: rgb(255, 0, 0)
                name: Azimut
                hold_action:
                  action: none
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: false
                show_icon: true
                icon: mdi:office-building
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 25px
                    - height: 25px
                tap_action:
                  action: none
                show_state: false
                name: Bureau
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_bureau
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_bureau
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_bureau
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_bureau
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_bureau
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_bureau
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      name:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      name:
                        - font-size: 12px
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_bureau
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_bureau
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_bureau
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_bureau
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_bureau
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_bureau
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_bureau
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: false
                show_icon: true
                icon: mdi:table-chair
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 25px
                    - height: 25px
                tap_action:
                  action: none
                show_state: false
                name: Bureau
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_sam
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_sam
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_sam
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_sam
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_sam
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_sam
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_sam
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_sam
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_sam
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_sam
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_sam
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_sam
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_sam
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: false
                show_icon: true
                icon: mdi:sofa
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 25px
                    - height: 25px
                tap_action:
                  action: none
                show_state: false
                name: Bureau
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_salon
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_salon
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_salon
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_salon
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_salon
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_salon
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_salon
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_salon
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_salon
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_salon
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_salon
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_salon
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_salon
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: false
                show_icon: true
                icon: mdi:water-pump
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 25px
                    - height: 25px
                tap_action:
                  action: none
                show_state: false
                name: Bureau
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_cuisine
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_cuisine
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_cuisine
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_cuisine
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_cuisine
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_cuisine
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_cuisine
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_cuisine
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_cuisine
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_cuisine
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_cuisine
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_cuisine
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_cuisine
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: true
                show_icon: true
                icon: mdi:bed
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - height: 50px
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 80px
                  name:
                    - font-size: 10px
                tap_action:
                  action: none
                show_state: false
                name: CH1
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_ch1
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_ch1
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_ch1
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_ch1
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_ch1
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_ch1
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_ch1
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_ch1
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_ch1
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_ch1
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_ch1
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_ch1
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_ch1
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: true
                show_icon: true
                icon: mdi:bed
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - height: 50px
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 80px
                  name:
                    - font-size: 10px
                tap_action:
                  action: none
                show_state: false
                name: CH2
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_ch2
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_ch2
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_ch2
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_ch2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_ch2
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_ch2
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_ch2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_ch2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_ch2
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_ch2
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_ch2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_ch2
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_ch2
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
          - type: vertical-stack
            cards:
              - type: custom:button-card
                show_name: true
                show_icon: true
                icon: mdi:bed
                styles:
                  card:
                    - height: 30px
                    - width: 50px
                  icon:
                    - height: 50px
                    - background-color: '#CCFFCC'
                    - color: rgb(38, 128, 199)
                    - width: 80px
                  name:
                    - font-size: 10px
                tap_action:
                  action: none
                show_state: false
                name: CH3
                hold_action:
                  action: none
              - type: custom:button-card
                icon: mdi:arrow-down-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_down_ch3
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:arrow-up-bold
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_up_ch3
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                icon: mdi:stop
                show_name: false
                show_icon: true
                tap_action:
                  action: toggle
                entity: input_boolean.volets_stop_ch3
                show_state: false
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                  icon:
                    - width: 25px
                    - height: 25px
              - type: custom:button-card
                entity: input_number.volets_niveau_ch3
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: '#CCFFCC'
                    - color: |
                        [[[
                          if (entity.state > 0 && entity.state < 100 )
                            return "rgb(0, 0, 0)";
                          else if (entity.state == 0)
                            return "'#FF0000'";
                          else
                            return '#00FF00';
                        ]]]
                state:
                  - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_matin_etat_ch3
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_matin_toggle_ch3
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ouvre_ch3
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ouvre_ch3
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(255, 253, 179)
                    - color: rgb(0, 0, 0)
                  state:
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_soir_etat_ch3
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
              - type: custom:button-card
                variables:
                  my_entity: input_boolean.volets_auto_soir_toggle_ch3
                show_name: true
                show_icon: false
                tap_action:
                  action: toggle
                entity: '[[[ return variables.my_entity; ]]]'
                show_state: false
                name: |
                  [[[ if (entity.state == "on")
                        return "Offset";
                      else
                        return "Heure";
                  ]]]
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  name:
                    - font-size: 12px
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
              - type: custom:button-card
                entity: input_datetime.volets_auto_time_ferme_ch3
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                entity: input_number.volets_auto_offset_ferme_ch3
                show_name: false
                show_icon: false
                show_state: true
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 255, 204)
                  state:
                    - color: rgb(0, 0, 0)
                    - font-size: 12px
              - type: custom:button-card
                show_name: false
                show_icon: false
                tap_action:
                  action: toggle
                entity: input_boolean.volets_auto_azimut_ch3
                show_state: true
                hold_action:
                  action: none
                styles:
                  card:
                    - height: 25px
                    - width: 50px
                    - background-color: rgb(204, 204, 255)
                state:
                  - value: 'on'
                    styles:
                      card:
                        - color: '#00FF00'
                      state:
                        - font-size: 12px
                  - value: 'off'
                    styles:
                      card:
                        - color: '#FF0000'
                      state:
                        - font-size: 10px
      - type: vertical-stack
        cards:
          - type: custom:button-card
            show_name: true
            entity: sensor.sun_next_rising
            name: Levé du soleil
            show_icon: false
            tap_action:
              action: none
            show_state: true
            hold_action:
              action: none
            styles:
              card:
                - height: 30px
              grid:
                - grid-template-areas: '"n s"'
                - grid-template-columns: 200px 200px
                - grid-template-rows: min-content min-content
              state:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
              name:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
            state:
              - name: '[[[return entity.state]]]'
          - type: custom:button-card
            show_name: true
            entity: sensor.sun_next_setting
            name: Couché du soleil
            show_icon: false
            tap_action:
              action: none
            show_state: true
            hold_action:
              action: none
            styles:
              card:
                - height: 35px
              grid:
                - grid-template-areas: '"n s"'
                - grid-template-columns: 200px 200px
                - grid-template-rows: min-content min-content
              state:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
              name:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
            state:
              - name: '[[[return entity.state]]]'
          - type: custom:button-card
            show_name: true
            entity: sensor.lavaur_daily_original_condition
            name: Météo Lavaur
            show_icon: false
            tap_action:
              action: none
            show_state: true
            hold_action:
              action: none
            styles:
              card:
                - height: 35px
              grid:
                - grid-template-areas: '"n s"'
                - grid-template-columns: 200px 200px
                - grid-template-rows: min-content min-content
              state:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
              name:
                - font-size: 12px
                - align-items: start
                - margin-top: '-10px'
            state:
              - name: '[[[return entity.state]]]'

Le flow

[{"id":"d8d288c742b5c81b","type":"subflow","name":"API Tuya iot","info":"# Gestion des APIs TUYA Iot\r\n\r\nAfin de faire fonctionner ce subflow, il faut lui passer le message de structure:\r\n\r\nmsg.tuya_api.client_id\r\nmsg.tuya_api.time        un timestamp\r\nmsg.tuya_api.device_id\r\nmsg.tuya_api.user_id\r\nmsg.tuya_api.commande    commande aiguillant entre ordre de configuration ou relevé de statut de l'entité.\r\nmsg.tuya_api.ordre       ordre à passer à l'entité\r\n\r\n","category":"smarthome","in":[{"x":100,"y":220,"wires":[{"id":"cc34878229ba459b"},{"id":"22c9308e64d572f2"}]}],"out":[{"x":1840,"y":620,"wires":[{"id":"eb7d0fb48dfeea11","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"6b3e51e7263bd40c","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Connexion1","func":"var url = \"https://openapi.tuyaeu.com/v1.0/token?grant_type=1\";\nvar t = msg.tuya_api.time;\nvar sign = msg.payload;\nvar client_id = msg.tuya_api.client_id;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"sign\": sign.toUpperCase(),\n },\n \n msg.payload = '';\n msg.url = url;\n msg.method = \"GET\";\n msg.tuya_api.sign_secret = sign;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":910,"y":220,"wires":[["046627bc0bc11fbb"]]},{"id":"046627bc0bc11fbb","type":"http request","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1110,"y":220,"wires":[["0ac904677470531b"]]},{"id":"cc34878229ba459b","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Create signStr","func":"let client_id = msg.tuya_api.client_id;\nlet t = msg.tuya_api.time;\n\nnode.status({fill:\"red\",shape:\"ring\",text:client_id});\nlet method = \"GET\";\nlet sign_url = \"/v1.0/token?grant_type=1\";\n\n// Couldn't get nodered to process an empty string so this is a hash of an empty file\nlet content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\nlet string_to_sign = method+\"\\n\"+content_hash+\"\\n\"+\"\"+\"\\n\"+sign_url;\nmsg.payload = client_id+t+string_to_sign;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":220,"wires":[["f3818dca4e177f69"]]},{"id":"f3818dca4e177f69","type":"hmac","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":690,"y":220,"wires":[["6b3e51e7263bd40c"]]},{"id":"0ac904677470531b","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Extract Token from Response","func":"var data = msg.payload;\nvar access = data.result.access_token;\nvar refresh = data.result.refresh_token;\n\n//msg.creds = {};\nmsg.tuya_api.access_token = access\nmsg.tuya_api.refresh_token = refresh;\n\nmsg.payload = msg.tuya_api.ordre;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1340,"y":220,"wires":[["f66948c2c5ba3d70"]]},{"id":"f66948c2c5ba3d70","type":"function","z":"d8d288c742b5c81b","name":"Liste des opérations","func":"if (msg.tuya_api.commande == 0){\n    return [msg,null];\n} else if (msg.tuya_api.commande == 1){\n    return [null,msg];\n}else {\n    node.warn(\"La valeur de la commande n'est pas connue\");\n}","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":460,"wires":[["0d8eb54a529bf85e","2064e8ad64cd37f6"],["6f079306406b226b","f30fdead3ce3856b"]],"outputLabels":["0","1"]},{"id":"ee971e8557275277","type":"function","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Connexion2","func":"let device_id = msg.tuya_api.device_id;\nlet url = \"https://openapi.tuyaeu.com/v1.0/devices/\" + device_id + \"/commands\";\nlet t = msg.time;\nlet client_id = msg.tuya_api.client_id;\nlet access_token = msg.tuya_api.access_token;\nlet sign = msg.payload;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"mode\" : \"cors\",\n \"Content-Type\": \"application/json\",\n \"sign\": sign.toUpperCase(),\n \"access_token\" : access_token,\n },\n\nmsg.payload = msg.tuya_api.ordre;\nmsg.url = url;\nmsg.method = \"POST\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1430,"y":420,"wires":[["6222843a323ae47f"]]},{"id":"6222843a323ae47f","type":"http request","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1610,"y":420,"wires":[["9c338d50728a3fc8","c75f94b3825f07bd"]]},{"id":"c730d9c21c85b6c1","type":"function","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Create signStr","func":"//let creds = flow.get(\"tuya\");\nlet access_token = msg.tuya_api.access_token;\nlet device_id = msg.tuya_api.device_id;\nlet t = msg.tuya_api.time;\nlet client_id = msg.tuya_api.client_id;\n\nlet method = \"POST\";\nlet sign_url = \"/v1.0/devices/\" + device_id + \"/commands\";\nlet content_hash = msg.payload;\n\nlet string_to_sign = method+\"\\n\"+content_hash+\"\\n\"+\"\"+\"\\n\"+sign_url;\nlet signStr = client_id + access_token + t + string_to_sign;\n\nmsg.payload = signStr;\n//msg.time = msg.time;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":940,"y":420,"wires":[["80f2ce055feca5f9"]]},{"id":"80f2ce055feca5f9","type":"hmac","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":1190,"y":420,"wires":[["ee971e8557275277"]]},{"id":"0d8eb54a529bf85e","type":"digest","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Hash the body data","algorithm":"SHA256","x":710,"y":420,"wires":[["c730d9c21c85b6c1"]]},{"id":"08e4cb4a36124ade","type":"comment","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Donner un ordre","info":"","x":480,"y":340,"wires":[]},{"id":"bfb85005e1a20a62","type":"comment","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Récupérer un token","info":"","x":490,"y":160,"wires":[]},{"id":"4ad7112320d38417","type":"function","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Connexion3","func":"let device_id = msg.tuya_api.device_id;\nlet url = \"https://openapi.tuyaeu.com/v1.0/devices/\" + device_id + \"/status\";\nlet t = msg.tuya_api.time;\nlet method = \"GET\";\nlet client_id = msg.tuya_api.client_id;\n//let creds = flow.get(\"tuya\");\nlet token = msg.tuya_api.access_token;\n//let sign = msg.payload;\nlet sign = msg.payload;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"mode\" : \"cors\",\n \"Content-Type\": \"application/json\",\n \"sign\": sign.toUpperCase(),\n \"access_token\" : token\n },\n\n msg.payload = '';\n msg.url = url;\n msg.method = \"GET\";\n \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":640,"wires":[["eb7d0fb48dfeea11"]]},{"id":"eb7d0fb48dfeea11","type":"http request","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1170,"y":640,"wires":[[]]},{"id":"174a610c49d94236","type":"comment","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Get Status Of Device","info":"","x":500,"y":580,"wires":[]},{"id":"9c338d50728a3fc8","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 309","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1870,"y":420,"wires":[]},{"id":"6f079306406b226b","type":"function","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Create signStr","func":"let access_token = msg.tuya_api.access_token;\nlet device_id = msg.tuya_api.device_id;\nlet t = msg.tuya_api.time;\nlet client_id = msg.tuya_api.client_id;\n\nlet method = \"GET\";\nlet sign_url = \"/v1.0/devices/\" + device_id + \"/status\";\nlet content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\nlet string_to_sign = method + \"\\n\" + content_hash + \"\\n\" + \"\" + \"\\n\" + sign_url;\nlet signStr = client_id + access_token + t + string_to_sign;\n\nmsg.payload = signStr;\n//msg.time = msg.tuya_api.time;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":640,"wires":[["b7dac392bb492edb"]]},{"id":"b7dac392bb492edb","type":"hmac","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":710,"y":640,"wires":[["4ad7112320d38417"]]},{"id":"22c9308e64d572f2","type":"debug","z":"d8d288c742b5c81b","d":true,"g":"4dfe7d10f3f1a3fb","name":"debug 336","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":80,"wires":[]},{"id":"2064e8ad64cd37f6","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 337","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":310,"y":340,"wires":[]},{"id":"f30fdead3ce3856b","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 338","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":250,"y":620,"wires":[]},{"id":"c75f94b3825f07bd","type":"delay","z":"d8d288c742b5c81b","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1260,"y":500,"wires":[["6f079306406b226b"]]},{"id":"cfd6cdedc4113f75","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["ee971e8557275277","6222843a323ae47f","c730d9c21c85b6c1","80f2ce055feca5f9","0d8eb54a529bf85e","08e4cb4a36124ade"],"x":374,"y":299},{"id":"4dfe7d10f3f1a3fb","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["6b3e51e7263bd40c","046627bc0bc11fbb","cc34878229ba459b","f3818dca4e177f69","0ac904677470531b","bfb85005e1a20a62","22c9308e64d572f2"],"x":294,"y":39},{"id":"6565106fc2673045","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["4ad7112320d38417","eb7d0fb48dfeea11","174a610c49d94236","6f079306406b226b","b7dac392bb492edb"],"x":374,"y":539},{"id":"ef69c7a52302b57c","type":"function","z":"575207865d1e30df","name":"Valeurs Entites","func":"var message = msg.entity_var;\n\nif (typeof (flow.get(msg.id)) === \"undefined\") {\n    flow.set(msg.id, {});\n}\n\nvar Pos = flow.get(msg.id);\nPos.tuya_api = {};\nlet Tuya = Pos.tuya_api;\nTuya.client_id = flow.get(\"tuya_client_id\");\nTuya.user_id = flow.get(\"tuya_user_id\");\nTuya.device_id = msg.device_id;\nTuya.time = msg.time;\n\nPos.action = msg.action;\n\nif (msg.action != 7){\n    msg.test = {};\n    let Id = flow.get(msg.id);\n    let valeur = {};\n    if (typeof (Id.positionnement) === \"undefined\") {\n        valeur.positionnement = {};\n        valeur.positionnement.pourcentage = null;\n        valeur.positionnement.new_position = null;\n        valeur.positionnement.new_azimut = Number(msg.azimut);\n        flow.set(msg.id, valeur);\n    }\n    Id.positionnement.new_azimut = Number(msg.azimut);\n    Tuya.commande = 0;\n\n    //Pos.entity_var = {};\n    let sortie = Pos.entity_var;\n    let message_length = message.length;\n    for (var i = 0; i < message_length; i++) {\n        if (message[i][\"entity_id\"].match(/volet['_'[a-z]]*/i)){\n            if (message[i][\"entity_id\"].match(/auto_offset_ouvre/i)){\n                //sortie['offset_ouv'] = Number(message[i][\"state\"]);\n                msg.offset_ouv = Number(message[i][\"state\"]);\n            } else if (message[i][\"entity_id\"].match(/auto_offset_ferme/i)) {\n                //sortie['offset_ferm'] = Number(message[i][\"state\"]);\n                msg.offset_ferm = Number(message[i][\"state\"]);\n            } else if (message[i][\"entity_id\"].match(/volets_auto_matin_toggle/i)) {\n                msg.toggle_m = message[i][\"state\"];\n            } else if (message[i][\"entity_id\"].match(/volets_auto_soir_toggle/i)) {\n                msg.toggle_s = message[i][\"state\"];\n            } else if (message[i][\"entity_id\"].match(/volets_auto_time_ouvre/i)) {\n                msg.time_m = message[i][\"state\"];\n            } else if (message[i][\"entity_id\"].match(/volets_auto_time_ferme/i)) {\n                msg.time_s = message[i][\"state\"];\n            }\n        }\n    }\n} else {\n    Tuya.commande = 1;\n}\n\n//msg.entity_var = {};\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1420,"y":360,"wires":[["a3cb30b1067bedd2","55c81f3ed234fc1d"]],"info":"Récupére les valeurs du tableau de bord liées à msg.id (une pièce)\r\n\r\nStructure les valeurs devant persister en mémoire."},{"id":"bcf894fa9b000b17","type":"ha-get-entities","z":"575207865d1e30df","name":"Liste entitées","server":"8ba7aec4.1022e","version":0,"rules":[{"property":"entity_id","logic":"jsonata","value":"$contains(\t   $entity().entity_id,\t   id\t)","valueType":"jsonata"}],"output_type":"array","output_empty_results":true,"output_location_type":"msg","output_location":"entity_var","output_results_count":1,"x":1210,"y":360,"wires":[["ef69c7a52302b57c"]]},{"id":"9b44297846ea637e","type":"function","z":"575207865d1e30df","name":"Action volet","func":"let Obj = flow.get(msg.id);\n\nif (Obj.action != 3 && Obj.action != 7) {\n\n// On vérifie que le volet ne soit pas déjà dans la bonne position\n  if (Obj.positionnement.pourcentage != Obj.positionnement.new_position) {\n    Obj.tuya_api.ordre = \"{ \\\"commands\\\": [{ \\\"code\\\" : \\\"percent_control\\\", \\\"value\\\" : \" + Obj.positionnement.pourcentage + \"}]}\";\n    //On bascule à 1 la variable \"act_ha\" pour dire au programme que l'action a été demandée par HA\n\n    Obj.act_ha = 1;\n    node.status({ fill: \"green\", text: \"Pourcent: \" + Obj.positionnement.pourcentage });\n    msg.tuya_api = Obj.tuya_api;\n    return msg;\n  }\n\n  node.status({ fill: \"green\", text: \"Dif: \" + Obj.action});\n\n} else if (Obj.action == 3) {\n  Obj.tuya_api.ordre = \"{ \\\"commands\\\" : [{ \\\"code\\\" : \\\"control\\\", \\\"value\\\" :  \\\"stop\\\"}]}\";\n  // On bascule à 1 la variable \"act_ha\" pour dire au programme que l'action a été demandée par HA\n\n  Obj.act_ha = 1;\n  node.status({ fill: \"red\", text: \"stop\"});\n  msg.tuya_api = Obj.tuya_api;\n  return msg;\n\n} else if (Obj.action == 7){\n\n  // On simule l'action hors HA en rafraichissant les valeurs depuis le cloud\n  Obj.act_ha = 0\n  msg.tuya_api = Obj.tuya_api;\n  node.status({ fill: \"yellow\", text: \"Refesh\" });\n  return msg;\n\n} else {\n    node.status({ fill: \"yellow\", text: \"Aucune action\" });\n}","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":2110,"y":340,"wires":[["c3ed1aa18958467a","9ed04df207b5aaa8"]],"info":"Modifie le payload afin de fournir au sous programme les bonnes informations à exécuter"},{"id":"3c9afc49bd7a370e","type":"function","z":"575207865d1e30df","name":"Global Settings CLICK On Start TAB","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"var client_id = \"Le Votre\";\nvar user_id = \"Le Votre\";\nflow.set(\"tuya_client_id\", client_id);\nflow.set(\"tuya_user_id\", user_id );\n\n","finalize":"","libs":[],"x":170,"y":40,"wires":[[]],"info":"L'objectif de cette fonction est de fournir les variables de connexion aux APIs\r\n\r\nLa récupération des valeurs est décrite [ici](https://forum.hacf.fr/t/api-tuya-depuis-node-red/28774/11)\r\n\r\nLes valeurs récupérées sont à saisir dans l'onglet \"On Start\"\r\n\r\n&ensp;&ensp;&ensp;&ensp;client_id\r\n\r\n&ensp;&ensp;&ensp;&ensp;user_id"},{"id":"488bbea2e3756767","type":"server-state-changed","z":"575207865d1e30df","name":"Elevation","server":"8ba7aec4.1022e","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"sensor.sunelevation","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"x":80,"y":80,"wires":[["b227b178e36761eb"]],"info":"Récupére le niveau d'élévation du soleil\r\n\r\nNecessite l'intégration \"sun\" de Home Assistant"},{"id":"b227b178e36761eb","type":"function","z":"575207865d1e30df","name":"Taux Ouverture","func":"var niveau;\n\nif (msg.payload > 20 && msg.payload <= 60) {\n    niveau = 80;\n} else if (msg.payload > 60) {\n    niveau = 65;\n} else {\n    niveau = 100;\n}\nnode.status({ fill: \"green\", text: niveau });\nmsg.payload = niveau;\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":80,"wires":[["b04f243b43f60dbd"]],"info":"Objectif\r\n\r\nFournir un taux d'élévation du volet en fonction du niveau d'élavation du soleil (msg.payload).\r\n\r\nCette donnée est utilisé par la suite par la fonction azimut\r\n\r\nDans une futur version elle sera potentiellement affectée directement à chaque volet"},{"id":"b04f243b43f60dbd","type":"change","z":"575207865d1e30df","name":"elevation","rules":[{"t":"set","p":"elevation","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":80,"wires":[[]],"info":"Instancie la variable flow.elevation"},{"id":"faf2848fb11e84f3","type":"server-state-changed","z":"575207865d1e30df","name":"azimut","server":"8ba7aec4.1022e","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"sensor.sunazimuth","entityIdType":"exact","outputInitially":false,"stateType":"num","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"2","valueType":"num"},{"property":"azimut","propertyType":"msg","value":"","valueType":"entityState"}],"x":70,"y":200,"wires":[["6d7265beda5e72f6"]],"info":"Récupére l'azimut du soleil\r\n\r\nNecessite l'intégration \"sun\" de Home Assistant"},{"id":"a3cb30b1067bedd2","type":"function","z":"575207865d1e30df","name":"Positionnement","func":"var Obj = flow.get(msg.id)\n\nif (Obj.action == 0) {\n    // Gestion de l'onverture\n    Obj.positionnement.pourcentage = 100;\n    return [msg, null, null];\n\n} else if (Obj.action == 1) {\n    // Gestion de la fermeture\n    Obj.positionnement.pourcentage = 0;\n    return [msg, null, null];\n\n} else if (Obj.action == 2){\n    \n    // Gestion de l'azimut\n    let azimut = Obj.positionnement.new_azimut;\n    let actual_position = Obj.positionnement.new_position;\n    let goal_position = Number(flow.get('elevation'));\n\n    if (Obj.entity_var.auto_azimut == \"on\") {\n        if ((azimut > msg.azi_min && azimut < msg.azi_max) && flow.get('meteo') == \"Ensoleillé\" ) {\n            if (actual_position != goal_position) {\n                // Le mouvement du volet va s'opérer en fonction de la variable pourcentage\n                \n                Obj.positionnement.pourcentage = goal_position;\n                node.status({ fill: \"green\", text: \"Niveau: \" + goal_position });\n                return [msg, null, null];\n            }\n        \n        } else if (actual_position != 100) {\n            //Si l'on est hors plage d'azimut, on rouvre le volet totalement si la fonction azimut est activée\n\n            Obj.positionnement.pourcentage = 100;\n            node.status({ fill: \"blue\", text: \"Niveau: 100\" });\n            return [msg, null, null];\n        \n        } else {\n            // Si on est hors plage d'azimut et que le volet est déjà ouvert\n            node.status({ fill: \"yellow\", text: \"Aucune action\" });\n        }\n    }\n} else if (Obj.action == 3){\n    //Gestion de l'arrêt. L'ordre est géré plus loin\n    return [msg, null, null];\n\n} else if (Obj.action == 4) {\n    // Gestion du taux d'ouverture\n    node.status({ fill: \"green\", text: \"Action 4\" });\n    Obj.positionnement.pourcentage = Number(msg.taux);\n    return [msg, null, null];\n\n} else if (Obj.action == 5) {\n    //Gestion de l'ouverture le matin\n    node.status({ fill: \"green\", text: \"Action 5\"});\n    //Bifurque afin de vérifier l'heure du matin\n    if (msg.toggle_m == \"on\") {\n        Obj.positionnement.pourcentage = 100;\n        return [null, msg, null];\n    } else {\n        //conversion de l'heure fourni en timestamp\n        let heure = msg.time_m;\n        let temp = heure.split(\":\");\n        let timestampheure = ((parseInt(temp[0]) * 60) + parseInt(temp[1])) * 60 + parseInt(temp[2]);\n\n        // Récupération du timestamp courant\n        temp = new Date();\n        heure = temp.getHours();\n        let minute = temp.getMinutes();\n        let seconde = temp.getSeconds();\n        let timestampcurrent = ((heure * 60) + minute) * 60 + seconde;\n        if (timestampheure >= (timestampcurrent - 120) && timestampheure <= (timestampcurrent + 120)){\n            Obj.positionnement.pourcentage = 100;\n            return [msg, null, null];\n        } else\n            node.status({ fill: \"yellow\", text: \"Action 5: Aucune action\" });\n    }\n\n} else if (Obj.action == 6) {\n    //Gestion de la fermeture le soir\n    node.status({ fill: \"green\", text: \"Action 6\" });\n    //Bifurque afin de vérifier l'heure du soir\n    if (msg.toggle_s == \"on\") {\n        Obj.positionnement.pourcentage = 0;\n        return [null, null, msg];\n    } else {\n        //conversion de l'heure fourni en timestamp\n        let heure = msg.time_s;\n        let temp = heure.split(\":\");\n        let timestampheure = ((parseInt(temp[0]) * 60) + parseInt(temp[1])) * 60 + parseInt(temp[2]);\n\n        // Récupération du timestamp courant\n        temp = new Date();\n        heure = temp.getHours();\n        let minute = temp.getMinutes();\n        let seconde = temp.getSeconds();\n        let timestampcurrent = ((heure * 60) + minute) * 60 + seconde;\n        if (timestampheure >= (timestampcurrent - 120) && timestampheure <= (timestampcurrent + 120)) {\n            Obj.positionnement.pourcentage = 0;\n            return [msg, null, null];\n        } else\n            node.status({ fill: \"yellow\", text: \"Action 5: Aucune action\" });\n    } \n\n} else if (Obj.action == 7) {\n    return [msg, null, null];\n}","outputs":3,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1660,"y":360,"wires":[["9b44297846ea637e","1b134a1d6e225401"],["d9afd42e8a5f2e7c"],["9270ef84952505bf"]],"outputLabels":["Manuelle","Offset_matin","Offset_soir"],"info":"En fonction du programme utilisé, affecte la valeur souhaitée à la variable:\r\n\r\npositionnement.pourcentage"},{"id":"4f2f91e4f7cb5039","type":"server-state-changed","z":"575207865d1e30df","name":"meteo","server":"8ba7aec4.1022e","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"sensor.lavaur_daily_original_condition","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"bouton","propertyType":"msg","value":"","valueType":"triggerId"}],"x":70,"y":140,"wires":[["59e4e624b1be226d"]],"info":"Récupére la météo du jour grace à l'intégration: \"Météo France\""},{"id":"59e4e624b1be226d","type":"change","z":"575207865d1e30df","name":"meteo","rules":[{"t":"set","p":"meteo","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":140,"wires":[[]],"info":"Instancie la variable flow.meteo"},{"id":"313b49b06ac1e4af","type":"function","z":"575207865d1e30df","name":"MàJ Pourcentage","func":"let message = msg.payload.result;\nlet message_length = message.length;\nlet Obj = flow.get(msg.id);\nlet Pos = Obj.positionnement;\n\nfor (var i = 0; i < message_length; i++) {\n    if (message[i][\"code\"].match(/percent_control/i)){\n        var new_value = message[i][\"value\"]\n    }\n}\n\n/* Si la nouvelle position détectée ne correspond pas à celle du progamme\non la met à jour et on poursuit sinon on s'arrête*/\nif (Pos.new_position != new_value) {\n    Pos.new_position = new_value;\n    return msg;\n}\n\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1530,"y":660,"wires":[["cbba7c7b1aa9746a","c14c62966e0fdac3","396c628523c91b01","1b7af5409c93858b","8a27ce7a9c763e14"]],"info":"Récupére la valeur d'ouverture en sortie de subflow afin de la comparer à la valeur stockée.\r\n\r\nCette fonction permet de mettre à jour la position du volet suite à une action manuelle sur l'interrupteur."},{"id":"4806e36ad01b37b4","type":"link out","z":"575207865d1e30df","name":"link out 76","mode":"link","links":["f16a017b0ec4ef0b","1f499c036878ca3e","76f4f86875a83812","3cc1417c9c0eab01","9137ca172d8be8f0","2b2892f6615c9809","27972266d1eca80b"],"x":555,"y":200,"wires":[]},{"id":"e5524eec8adfea50","type":"link in","z":"575207865d1e30df","name":"link in 60","links":["3435c1ac287473d5","431c7f2132e0d0f9","bd66fda3ba2151fd","30a7d41c6c5944f5","d4cfba64cb3b75b7","fde8f0f2e7758b9c","2d630bf2cd0534a2"],"x":1095,"y":360,"wires":[["bcf894fa9b000b17"]]},{"id":"6d7265beda5e72f6","type":"api-current-state","z":"575207865d1e30df","name":"Azimut auto global","server":"8ba7aec4.1022e","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.volets_auto_azimut_global","state_type":"str","blockInputOverrides":false,"outputProperties":[],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":330,"y":200,"wires":[["4806e36ad01b37b4"],[]],"info":"Récupére le commutateur input_boolean.volets_auto_azimut_global\r\n\r\nSi ce dernier est activé, donc à \"on\" ou **noir** dans l'interface, on continue le programme\r\n\r\nSi ce dernier est désactivé, donc à \"off\" ou **rouge** dans l'interface, on arrête le programme"},{"id":"d9afd42e8a5f2e7c","type":"within-time-switch","z":"575207865d1e30df","name":"Plage matin","nameInt":"","positionConfig":"403a6e4bd797cb6e","startTime":"sunriseStart","startTimeType":"pdsTime","startOffset":"offset_ouv","startOffsetType":"msg","startOffsetMultiplier":60000,"endTime":"sunriseEnd","endTimeType":"pdsTime","endOffset":"offset_ouv","endOffsetType":"msg","endOffsetMultiplier":60000,"timeRestrictions":0,"timeRestrictionsType":"none","timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeOnlyOddWeeks":false,"timeOnlyEvenWeeks":false,"timeMonths":"*","timedatestart":"","timedateend":"","propertyStart":"","propertyStartType":"none","propertyStartCompare":"true","propertyStartThreshold":"","propertyStartThresholdType":"num","startTimeAlt":"","startTimeAltType":"entered","startOffsetAlt":0,"startOffsetAltType":"none","startOffsetAltMultiplier":60000,"propertyEnd":"","propertyEndType":"none","propertyEndCompare":"true","propertyEndThreshold":"","propertyEndThresholdType":"num","endTimeAlt":"","endTimeAltType":"entered","endOffsetAlt":0,"endOffsetAltType":"none","endOffsetAltMultiplier":60000,"withinTimeValue":"","withinTimeValueType":"msgInput","outOfTimeValue":"false","outOfTimeValueType":"msgInput","tsCompare":"0","x":1870,"y":380,"wires":[["9b44297846ea637e"],[]]},{"id":"9270ef84952505bf","type":"within-time-switch","z":"575207865d1e30df","name":"Plage soir","nameInt":"","positionConfig":"403a6e4bd797cb6e","startTime":"sunsetStart","startTimeType":"pdsTime","startOffset":"offset_ferm","startOffsetType":"msg","startOffsetMultiplier":60000,"endTime":"sunsetEnd","endTimeType":"pdsTime","endOffset":"offset_ferm","endOffsetType":"msg","endOffsetMultiplier":60000,"timeRestrictions":0,"timeRestrictionsType":"none","timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeOnlyOddWeeks":false,"timeOnlyEvenWeeks":false,"timeMonths":"*","timedatestart":"","timedateend":"","propertyStart":"","propertyStartType":"none","propertyStartCompare":"true","propertyStartThreshold":"","propertyStartThresholdType":"num","startTimeAlt":"","startTimeAltType":"entered","startOffsetAlt":0,"startOffsetAltType":"none","startOffsetAltMultiplier":60000,"propertyEnd":"","propertyEndType":"none","propertyEndCompare":"true","propertyEndThreshold":"","propertyEndThresholdType":"num","endTimeAlt":"","endTimeAltType":"entered","endOffsetAlt":0,"endOffsetAltType":"none","endOffsetAltMultiplier":60000,"withinTimeValue":"","withinTimeValueType":"msgInput","outOfTimeValue":"false","outOfTimeValueType":"msgInput","tsCompare":"0","x":1860,"y":440,"wires":[["9b44297846ea637e"],[]]},{"id":"27ba68ad4922f686","type":"debug","z":"575207865d1e30df","name":"debug 339","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1530,"y":600,"wires":[]},{"id":"1b134a1d6e225401","type":"debug","z":"575207865d1e30df","name":"debug 340","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1870,"y":240,"wires":[]},{"id":"c3ed1aa18958467a","type":"debug","z":"575207865d1e30df","name":"debug 341","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2290,"y":240,"wires":[]},{"id":"55c81f3ed234fc1d","type":"debug","z":"575207865d1e30df","name":"debug 342","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1630,"y":240,"wires":[]},{"id":"9ed04df207b5aaa8","type":"link out","z":"575207865d1e30df","name":"link out 87","mode":"link","links":["4a0fc73bdbded94d"],"x":2325,"y":340,"wires":[]},{"id":"4a0fc73bdbded94d","type":"link in","z":"575207865d1e30df","name":"link in 68","links":["9ed04df207b5aaa8"],"x":1105,"y":660,"wires":[["a30910a7616af66a"]]},{"id":"ef8678a601244c43","type":"debug","z":"575207865d1e30df","name":"debug 349","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":930,"y":220,"wires":[]},{"id":"8a27ce7a9c763e14","type":"debug","z":"575207865d1e30df","name":"debug 350","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1770,"y":860,"wires":[]},{"id":"a30910a7616af66a","type":"subflow:d8d288c742b5c81b","z":"575207865d1e30df","name":"","x":1290,"y":660,"wires":[["313b49b06ac1e4af","27ba68ad4922f686"]]},{"id":"10ef606d1ddfc682","type":"group","z":"575207865d1e30df","name":"","style":{"fill":"#ffffbf","fill-opacity":"0.72","label":true},"nodes":["1b7af5409c93858b","c14c62966e0fdac3","396c628523c91b01","92c53ced5c6ddbb4","cbba7c7b1aa9746a","d36b022c2220db5c","1fe263b910724190"],"x":1754,"y":539,"w":712,"h":262},{"id":"1b7af5409c93858b","type":"function","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"Texte_Log","func":"let Obj = flow.get(msg.id);\nvar elevation = Obj.positionnement.pourcentage;\n\nnode.status({ fill: \"green\", text: Obj.act_ha });\n\nif ( Obj.act_ha == 1 ){\n    if ( Obj.action == 0 ){\n        msg.bouton = \"Ouverture\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 1) {\n        msg.bouton = \"Fermeture\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 2) {\n        msg.bouton = \"Azimut\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 3) {\n        msg.bouton = \"Stop\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 4) {\n        msg.bouton = \"Taux d'ouverture\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 5) {\n        msg.bouton = \"Ouverture auto\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    } else if (Obj.action == 6) {\n        msg.bouton = \"Fermeture auto\";\n        msg.etat = \"Enclenché\";\n        msg.message = \"Action HA\"\n    }\n}else if (Obj.act_ha == 0) {\n    msg.bouton = \"Boutons physiques\";\n    msg.etat = \"Enclenché\";\n    msg.message = \"Action hors HA\"\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1850,"y":760,"wires":[["1fe263b910724190"]],"info":"Fonction gérant le log des actions demandées au volet"},{"id":"c14c62966e0fdac3","type":"function","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"Changement  affichage Niveau","func":"let Obj = flow.get(msg.id);\nlet Pos = Obj.positionnement;\n\n//context.flow.set(\"pourcentage\", msg.payload, \"default\");\nlet entite = \"input_number.volets_niveau_\" + msg.id;\nmsg.payload = {\n    domain: \"input_number\",\n    service: \"set_value\",\n    target: {\n        \"entity_id\": [entite]\n    },\n    data: {\n        \"value\": Pos.new_position\n    }\n}\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1910,"y":640,"wires":[["92c53ced5c6ddbb4"]],"info":"MAJ de la valeur pourcentage du tableau de bord non mise à jour en cas de déclenchement manuel\r\nIl est considéré que les actions par défaut sont réalisées par boutons physiques donc hors HA"},{"id":"396c628523c91b01","type":"function","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"Changement Etat Bouton","func":"let Obj = flow.get(msg.id)\n\nif (Obj.action == 0) {\n    let entite = \"input_boolean.volets_up_\" + msg.id;\n    msg.payload = {\n        \"domain\": \"input_boolean\",\n        \"service\": \"turn_off\",\n        \"target\": {\n            \"entity_id\": [entite]\n        }\n    }\n    node.status({ fill: \"blue\", text: \"Bascule up\" });\n    return msg;\n} else if (Obj.action == 1) {\n    let entite = \"input_boolean.volets_down_\" + msg.id;\n    msg.payload = {\n        \"domain\": \"input_boolean\",\n        \"service\": \"turn_off\",\n        \"target\": {\n            \"entity_id\": [entite]\n        }\n    }\n    node.status({ fill: \"blue\", text: \"Bascule down\" });\n    return msg;\n} else if (Obj.action == 3 ) {\n    let entite = \"input_boolean.volets_stop_\" + msg.id;\n    msg.payload = {\n        domain: \"input_boolean\",\n        service: \"turn_off\",\n        target: {\n            entity_id: [entite]\n        }\n    }\n    node.status({ fill: \"blue\", text: \"stop\"});\n    return msg;\n}\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1890,"y":700,"wires":[["92c53ced5c6ddbb4"]],"info":"Fonction permettant de rebasculer les boutons au statut off après leur activation"},{"id":"92c53ced5c6ddbb4","type":"api-call-service","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"","server":"8ba7aec4.1022e","version":5,"debugenabled":false,"domain":"","service":"","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":2210,"y":640,"wires":[["d36b022c2220db5c"]]},{"id":"cbba7c7b1aa9746a","type":"function","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"Changement azimut Bouton","func":"//var message = msg.payload;\nlet Obj = flow.get(msg.id);\n\n/* Si le volet s'ouvre à 100%, la fonction azimut est automatiquement basculée à activé*/\nif (Obj.new_position == 100 ) {\n    let entite = \"input_boolean.volets_auto_azimut_\" + msg.id;\n    msg.payload = {\n        domain: \"input_boolean\",\n        service: \"turn_on\",\n        target: {\n            entity_id: [entite]\n        }\n    }\n    node.status({ fill: \"green\", text: Obj.new_position });\n    return msg;\n\n/*Si le volet n'est pas ouvert totalement et qu'on n'est pas sur une action automatique,\n  la fonction azimut est désactivée. C'est le cas ou on ouvre puis on décide d'appuyer sur le bouton\n  pour refermer partiellement le volet*/\n} else if (Obj.new_position != 100 && Number(Obj.action) != 2){\n    let entite = \"input_boolean.volets_auto_azimut_\" + msg.id;\n    msg.payload = {\n        domain: \"input_boolean\",\n        service: \"turn_off\",\n        target: {\n            entity_id: [entite]\n        }\n    }\n    node.status({ fill: \"red\", text: Obj.new_position });\n    return msg;\n} else {\n    node.status({ fill: \"yellow\", text: \"Aucune action\" });\n}","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1900,"y":580,"wires":[["92c53ced5c6ddbb4"]],"info":"Gére l'activation ou non de la fonction d'ouverture en fonction de l'azimut.\r\n\r\nActive la fonction azimut du volet lors de l'ouverture total de ce dernier. (valeur à 0)\r\n\r\nSi le volet n'est ouvert que partiellement, la fonction ne s'active pas."},{"id":"d36b022c2220db5c","type":"function","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"Réinit","func":"/*Réinitialisation de la variable \"act_ha\" à 0 pour les actions futures*/\nlet Obj = flow.get(msg.id);\nObj.act_ha = 0;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":2390,"y":640,"wires":[[]],"info":"Réinitialise la valeur de la variable act_ha"},{"id":"1fe263b910724190","type":"link out","z":"575207865d1e30df","g":"10ef606d1ddfc682","name":"link out 75","mode":"link","links":["48825624e6296d2c"],"x":2225,"y":760,"wires":[]},{"id":"938e591897d41c86","type":"group","z":"575207865d1e30df","name":"Log","style":{"fill":"#bfc7d7","label":true},"nodes":["189e9256ad86a588","efd7bd80b868a635","48825624e6296d2c"],"x":1874,"y":839,"w":552,"h":82},{"id":"189e9256ad86a588","type":"file","z":"575207865d1e30df","g":"938e591897d41c86","name":"log","filename":"filename","filenameType":"msg","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":2350,"y":880,"wires":[[]],"info":"Le log et écrit dans un fichier mensuel dans /config/logs/\"Id\""},{"id":"efd7bd80b868a635","type":"function","z":"575207865d1e30df","g":"938e591897d41c86","name":"Horodatage de la ligne de log","func":"let Obj = flow.get(msg.id);\nlet message = msg.message + \" \" + msg.bouton + \": \" + msg.etat + \"; Niveau: \" + Obj.positionnement.new_position;\n\nconst temp = new Date();\nlet annee = (temp.getFullYear().toString());\nlet mois = (temp.getMonth() + 1).toString().padStart(2, \"0\");\nlet jour = (temp.getDate().toString().padStart(2, \"0\"));\nlet heure = (temp.getHours().toString().padStart(2, \"0\"));\nlet minute = (temp.getMinutes().toString().padStart(2, \"0\"));\nlet seconde = (temp.getSeconds().toString().padStart(2, \"0\"));\n\nlet datetemp = annee + \"-\" + mois;\nmsg.filename =  \"/config/logs/\" + datetemp + \"_\" + msg.id + \".log\";\n\n\nlet horodatage = annee + \"-\" + mois + \"-\" + jour + \"_\" + heure + \":\" + minute + \":\" + seconde;\nnode.status({ fill: \"blue\", text: horodatage });\n\nmsg.payload = horodatage + \" \"+  message;\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":2100,"y":880,"wires":[["189e9256ad86a588"]]},{"id":"48825624e6296d2c","type":"link in","z":"575207865d1e30df","g":"938e591897d41c86","name":"link in 62","links":["1fe263b910724190"],"x":1915,"y":880,"wires":[["efd7bd80b868a635"]]},{"id":"cf0c264bd8d76173","type":"group","z":"575207865d1e30df","name":"Bureau","style":{"label":true},"nodes":["752a5de99c6ff80d","5987584cd85ac344","58b9fa0fb36ccf93","2944f56e19118bea","5d0d3ef7668a4ccc","ed4b55973ab44531","774b0f631c34df85","f16a017b0ec4ef0b","3435c1ac287473d5","5574b4a7301e429b","4ed1092604d4f241","1dca3aa3afcef4d4","838abe6fd5394eba"],"x":14,"y":259,"w":922,"h":482},{"id":"752a5de99c6ff80d","type":"server-state-changed","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Fermeture volet","server":"8ba7aec4.1022e","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"input_boolean.volets_down_bureau","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"on","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"1","valueType":"num"}],"x":120,"y":400,"wires":[["2944f56e19118bea"],[]],"info":"Récupére le statut du bouton de fermeture du volet\r\n\r\nEntité:\r\n\r\ninput_boolean.volets_down_bureau"},{"id":"5987584cd85ac344","type":"server-state-changed","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Ouverture volet","server":"8ba7aec4.1022e","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"input_boolean.volets_up_bureau","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"on","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"0","valueType":"num"}],"x":120,"y":340,"wires":[["2944f56e19118bea"],[]],"info":"Récupére le statut du bouton d'ouverture du volet\r\n\r\nEntité:\r\n\r\ninput_boolean.volets_up_bureau"},{"id":"58b9fa0fb36ccf93","type":"server-state-changed","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Arrêt ouverture","server":"8ba7aec4.1022e","version":5,"outputs":2,"exposeAsEntityConfig":"","entityId":"input_boolean.volets_stop_bureau","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"on","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"3","valueType":"num"}],"x":120,"y":460,"wires":[["2944f56e19118bea"],[]],"info":"Récupére le statut du bouton stop du volet\r\n\r\nEntité:\r\n\r\ninput_boolean.volets_stop_bureau"},{"id":"2944f56e19118bea","type":"change","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Valeurs communes","rules":[{"t":"set","p":"device_id","pt":"msg","to":"Le votre","tot":"str"},{"t":"set","p":"time","pt":"msg","to":"","tot":"date"},{"t":"set","p":"id","pt":"msg","to":"bureau","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":710,"y":400,"wires":[["3435c1ac287473d5","ef8678a601244c43"]],"info":"Injecte les valeurs pour les variables suivantes:\r\n\r\n&ensp;&ensp;&ensp;&ensp;device_id: Id du module à piloter\r\n\r\n&ensp;&ensp;&ensp;&ensp;time: un timestamp\r\n\r\n&ensp;&ensp;&ensp;&ensp;Id: le nom de la pièce où est situé l'entité à piloter."},{"id":"5d0d3ef7668a4ccc","type":"time-inject","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"","nameInt":"timestamp ↻1min","positionConfig":"403a6e4bd797cb6e","props":[{"p":"","pt":"msgPayload","v":"","vt":"date","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":true,"days":"*","months":"*","onlyOddDays":false,"onlyEvenDays":false,"onlyOddWeeks":false,"onlyEvenWeeks":false}],"injectTypeSelect":"interval","intervalCount":"1","intervalCountType":"num","intervalCountMultiplier":60000,"cron":"","cronType":"cronexpr","time":"","timeType":"entered","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeOnlyOddWeeks":false,"timeOnlyEvenWeeks":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltOnlyOddWeeks":false,"timeAltOnlyEvenWeeks":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"recalcTime":2,"x":140,"y":580,"wires":[["ed4b55973ab44531"]]},{"id":"ed4b55973ab44531","type":"api-current-state","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Matin auto","server":"8ba7aec4.1022e","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.volets_auto_matin_etat_bureau","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"5","valueType":"num"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":350,"y":580,"wires":[["2944f56e19118bea"],[]],"info":"La fonction d'ouverture automatique du volet le matin\r\n\r\nLa fonction est activée toutes les minutes afin d'entrer dans la plage d'ouverture solaire du noeud \"Plage Matin\""},{"id":"774b0f631c34df85","type":"api-current-state","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Soir auto","server":"8ba7aec4.1022e","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_boolean.volets_auto_soir_etat_bureau","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"action","propertyType":"msg","value":"6","valueType":"num"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":360,"y":640,"wires":[["2944f56e19118bea"],[]],"info":"La fonction d'ouverture automatique du volet le soir\r\n\r\nLa fonction est activée toutes les minutes afin d'entrer dans la plage d'ouverture solaire du noeud \"Plage soir\""},{"id":"f16a017b0ec4ef0b","type":"link in","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"link in 57","links":["4806e36ad01b37b4"],"x":65,"y":700,"wires":[["838abe6fd5394eba"]]},{"id":"3435c1ac287473d5","type":"link out","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"link out 79","mode":"link","links":["e5524eec8adfea50"],"x":895,"y":400,"wires":[]},{"id":"5574b4a7301e429b","type":"inject","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Refresh statut","props":[{"p":"action","v":"7","vt":"num"}],"repeat":"300","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":300,"wires":[["2944f56e19118bea"]]},{"id":"4ed1092604d4f241","type":"time-inject","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"","nameInt":"timestamp ↻1min","positionConfig":"403a6e4bd797cb6e","props":[{"p":"","pt":"msgPayload","v":"","vt":"date","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":true,"days":"*","months":"*","onlyOddDays":false,"onlyEvenDays":false,"onlyOddWeeks":false,"onlyEvenWeeks":false}],"injectTypeSelect":"interval","intervalCount":"1","intervalCountType":"num","intervalCountMultiplier":60000,"cron":"","cronType":"cronexpr","time":"","timeType":"entered","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeOnlyOddWeeks":false,"timeOnlyEvenWeeks":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltOnlyOddWeeks":false,"timeAltOnlyEvenWeeks":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"recalcTime":2,"x":140,"y":640,"wires":[["774b0f631c34df85"]]},{"id":"1dca3aa3afcef4d4","type":"server-state-changed","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Poucentage d'ouverture","server":"8ba7aec4.1022e","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"input_number.volets_niveau_bureau","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"taux","propertyType":"msg","value":"","valueType":"entityState"},{"property":"action","propertyType":"msg","value":"4","valueType":"str"}],"x":140,"y":520,"wires":[["2944f56e19118bea"]],"info":"Récupére le pourcentage d'ouverture désiré du volet\r\n\r\nEntité:\r\n\r\ninput_number.volets_niveau_bureau"},{"id":"838abe6fd5394eba","type":"change","z":"575207865d1e30df","g":"cf0c264bd8d76173","name":"Plage d'azimut","rules":[{"t":"set","p":"azi_min","pt":"msg","to":"160","tot":"num"},{"t":"set","p":"azi_max","pt":"msg","to":"226","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":700,"wires":[["2944f56e19118bea"]],"info":"Utilisé par la fonction Azimut, il récupére la valeur max et min de la plage d'azimut pour cette fenêtre"},{"id":"8ba7aec4.1022e","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true},{"id":"403a6e4bd797cb6e","type":"position-config","name":"Domicile ","isValide":"true","angleType":"deg","timeZoneOffset":"99","timeZoneDST":"0","stateTimeFormat":"3","stateDateFormat":"12","contextStore":""}]

Le sous-flow

[{"id":"d8d288c742b5c81b","type":"subflow","name":"API Tuya iot","info":"# Gestion des APIs TUYA Iot\r\n\r\nAfin de faire fonctionner ce subflow, il faut lui passer le message de structure:\r\n\r\nmsg.tuya_api.client_id\r\nmsg.tuya_api.time        un timestamp\r\nmsg.tuya_api.device_id\r\nmsg.tuya_api.user_id\r\nmsg.tuya_api.commande    commande aiguillant entre ordre de configuration ou relevé de statut de l'entité.\r\nmsg.tuya_api.ordre       ordre à passer à l'entité\r\n\r\n","category":"smarthome","in":[{"x":100,"y":220,"wires":[{"id":"cc34878229ba459b"},{"id":"22c9308e64d572f2"}]}],"out":[{"x":1840,"y":620,"wires":[{"id":"eb7d0fb48dfeea11","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"cfd6cdedc4113f75","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["ee971e8557275277","6222843a323ae47f","c730d9c21c85b6c1","80f2ce055feca5f9","0d8eb54a529bf85e","08e4cb4a36124ade"],"x":374,"y":299,"w":1332,"h":162},{"id":"4dfe7d10f3f1a3fb","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["6b3e51e7263bd40c","046627bc0bc11fbb","cc34878229ba459b","f3818dca4e177f69","0ac904677470531b","bfb85005e1a20a62","22c9308e64d572f2"],"x":294,"y":39,"w":1192,"h":222},{"id":"6565106fc2673045","type":"group","z":"d8d288c742b5c81b","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["4ad7112320d38417","eb7d0fb48dfeea11","174a610c49d94236","6f079306406b226b","b7dac392bb492edb"],"x":374,"y":539,"w":892,"h":142},{"id":"6b3e51e7263bd40c","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Connexion1","func":"var url = \"https://openapi.tuyaeu.com/v1.0/token?grant_type=1\";\nvar t = msg.tuya_api.time;\nvar sign = msg.payload;\nvar client_id = msg.tuya_api.client_id;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"sign\": sign.toUpperCase(),\n },\n \n msg.payload = '';\n msg.url = url;\n msg.method = \"GET\";\n msg.tuya_api.sign_secret = sign;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":910,"y":220,"wires":[["046627bc0bc11fbb"]]},{"id":"046627bc0bc11fbb","type":"http request","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1110,"y":220,"wires":[["0ac904677470531b"]]},{"id":"cc34878229ba459b","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Create signStr","func":"let client_id = msg.tuya_api.client_id;\nlet t = msg.tuya_api.time;\n\nnode.status({fill:\"red\",shape:\"ring\",text:client_id});\nlet method = \"GET\";\nlet sign_url = \"/v1.0/token?grant_type=1\";\n\n// Couldn't get nodered to process an empty string so this is a hash of an empty file\nlet content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\nlet string_to_sign = method+\"\\n\"+content_hash+\"\\n\"+\"\"+\"\\n\"+sign_url;\nmsg.payload = client_id+t+string_to_sign;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":220,"wires":[["f3818dca4e177f69"]]},{"id":"f3818dca4e177f69","type":"hmac","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":690,"y":220,"wires":[["6b3e51e7263bd40c"]]},{"id":"0ac904677470531b","type":"function","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Extract Token from Response","func":"var data = msg.payload;\nvar access = data.result.access_token;\nvar refresh = data.result.refresh_token;\n\n//msg.creds = {};\nmsg.tuya_api.access_token = access\nmsg.tuya_api.refresh_token = refresh;\n\nmsg.payload = msg.tuya_api.ordre;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1340,"y":220,"wires":[["f66948c2c5ba3d70"]]},{"id":"f66948c2c5ba3d70","type":"function","z":"d8d288c742b5c81b","name":"Liste des opérations","func":"if (msg.tuya_api.commande == 0){\n    return [msg,null];\n} else if (msg.tuya_api.commande == 1){\n    return [null,msg];\n}else {\n    node.warn(\"La valeur de la commande n'est pas connue\");\n}","outputs":2,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":460,"wires":[["0d8eb54a529bf85e","2064e8ad64cd37f6"],["6f079306406b226b","f30fdead3ce3856b"]],"outputLabels":["0","1"]},{"id":"ee971e8557275277","type":"function","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Connexion2","func":"let device_id = msg.tuya_api.device_id;\nlet url = \"https://openapi.tuyaeu.com/v1.0/devices/\" + device_id + \"/commands\";\nlet t = msg.time;\nlet client_id = msg.tuya_api.client_id;\nlet access_token = msg.tuya_api.access_token;\nlet sign = msg.payload;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"mode\" : \"cors\",\n \"Content-Type\": \"application/json\",\n \"sign\": sign.toUpperCase(),\n \"access_token\" : access_token,\n },\n\nmsg.payload = msg.tuya_api.ordre;\nmsg.url = url;\nmsg.method = \"POST\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1430,"y":420,"wires":[["6222843a323ae47f"]]},{"id":"6222843a323ae47f","type":"http request","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1610,"y":420,"wires":[["9c338d50728a3fc8","c75f94b3825f07bd"]]},{"id":"c730d9c21c85b6c1","type":"function","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Create signStr","func":"//let creds = flow.get(\"tuya\");\nlet access_token = msg.tuya_api.access_token;\nlet device_id = msg.tuya_api.device_id;\nlet t = msg.tuya_api.time;\nlet client_id = msg.tuya_api.client_id;\n\nlet method = \"POST\";\nlet sign_url = \"/v1.0/devices/\" + device_id + \"/commands\";\nlet content_hash = msg.payload;\n\nlet string_to_sign = method+\"\\n\"+content_hash+\"\\n\"+\"\"+\"\\n\"+sign_url;\nlet signStr = client_id + access_token + t + string_to_sign;\n\nmsg.payload = signStr;\n//msg.time = msg.time;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":940,"y":420,"wires":[["80f2ce055feca5f9"]]},{"id":"80f2ce055feca5f9","type":"hmac","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":1190,"y":420,"wires":[["ee971e8557275277"]]},{"id":"0d8eb54a529bf85e","type":"digest","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Hash the body data","algorithm":"SHA256","x":710,"y":420,"wires":[["c730d9c21c85b6c1"]]},{"id":"08e4cb4a36124ade","type":"comment","z":"d8d288c742b5c81b","g":"cfd6cdedc4113f75","name":"Donner un ordre","info":"","x":480,"y":340,"wires":[]},{"id":"bfb85005e1a20a62","type":"comment","z":"d8d288c742b5c81b","g":"4dfe7d10f3f1a3fb","name":"Récupérer un token","info":"","x":490,"y":160,"wires":[]},{"id":"4ad7112320d38417","type":"function","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Connexion3","func":"let device_id = msg.tuya_api.device_id;\nlet url = \"https://openapi.tuyaeu.com/v1.0/devices/\" + device_id + \"/status\";\nlet t = msg.tuya_api.time;\nlet method = \"GET\";\nlet client_id = msg.tuya_api.client_id;\n//let creds = flow.get(\"tuya\");\nlet token = msg.tuya_api.access_token;\n//let sign = msg.payload;\nlet sign = msg.payload;\n\nmsg.headers ={\n \"sign_method\": \"HMAC-SHA256\",\n \"client_id\" : client_id,\n \"t\": t.toString(),\n \"mode\" : \"cors\",\n \"Content-Type\": \"application/json\",\n \"sign\": sign.toUpperCase(),\n \"access_token\" : token\n },\n\n msg.payload = '';\n msg.url = url;\n msg.method = \"GET\";\n \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":640,"wires":[["eb7d0fb48dfeea11"]]},{"id":"eb7d0fb48dfeea11","type":"http request","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1170,"y":640,"wires":[[]]},{"id":"174a610c49d94236","type":"comment","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Get Status Of Device","info":"","x":500,"y":580,"wires":[]},{"id":"9c338d50728a3fc8","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 309","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1870,"y":420,"wires":[]},{"id":"6f079306406b226b","type":"function","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Create signStr","func":"let access_token = msg.tuya_api.access_token;\nlet device_id = msg.tuya_api.device_id;\nlet t = msg.tuya_api.time;\nlet client_id = msg.tuya_api.client_id;\n\nlet method = \"GET\";\nlet sign_url = \"/v1.0/devices/\" + device_id + \"/status\";\nlet content_hash = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\nlet string_to_sign = method + \"\\n\" + content_hash + \"\\n\" + \"\" + \"\\n\" + sign_url;\nlet signStr = client_id + access_token + t + string_to_sign;\n\nmsg.payload = signStr;\n//msg.time = msg.tuya_api.time;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":640,"wires":[["b7dac392bb492edb"]]},{"id":"b7dac392bb492edb","type":"hmac","z":"d8d288c742b5c81b","g":"6565106fc2673045","name":"Sign signStr with secret","algorithm":"HmacSHA256","key":"58fb24515a07454886120147b4225450","x":710,"y":640,"wires":[["4ad7112320d38417"]]},{"id":"22c9308e64d572f2","type":"debug","z":"d8d288c742b5c81b","d":true,"g":"4dfe7d10f3f1a3fb","name":"debug 336","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":390,"y":80,"wires":[]},{"id":"2064e8ad64cd37f6","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 337","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":310,"y":340,"wires":[]},{"id":"f30fdead3ce3856b","type":"debug","z":"d8d288c742b5c81b","d":true,"name":"debug 338","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":250,"y":620,"wires":[]},{"id":"c75f94b3825f07bd","type":"delay","z":"d8d288c742b5c81b","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1260,"y":500,"wires":[["6f079306406b226b"]]}]

Avant d’entrer dans les détails, sachez que chaque nœud contient une description de son fonctionnement. Je pense pas en avoir oublié. Si tel était le cas merci de me le signaler que je corrige/complète.

1. Global Settings CLICK On Start TAB

C’est le premier nœud à corriger. La procédure pour récupérer les valeurs est Ici.

2. Taux Ouverture

C’est dans cette fonction que vous gérez le niveau d’ouverture du volet en fonction de sa position dans le ciel. Elle est utilisé par la fonction Azimut.

3. Valeurs communes

Stocke les valeurs propres à ce volet. Il est impératif de changer les valeurs à l’intérieur pour qu’elles correspondent à votre environnement.

4. Plage d’Azimut

Détermine qu’elle sera la plage d’Azimut pendant laquelle la fonction s’enclenchera.

Une dernière chose le groupe Bureau est à dupliquer et modifier pour chaque volet.

Voila en espérant que cela pourra servir. Je me permets 2 bémols au fonctionnement

  • Il peut arriver que le volet ne réagisse pas, c’est certainement que le module s’est « perdu » pour je ne sais quelle raison. Dans ce cas, enclencher l’ordre d’Ouverture ou de Fermeture attendre qu’il claque puis relancer c’est reparti.
  • L’azimut étant mouvant en fonction de l’année, les valeurs sont à recalculer régulièrement aide. Je travaille sur une fonction qui calculera la position azimut en fonction d’une valeur de référence. Si jamais j’y arrive, je l’ajouterai à ce post.

Voilà n’hésitez pas à me faire vos remarques si certaines choses ne sont pas claires ou si vous voulez plus d’explication.

Passer une bonne journée

2 « J'aime »