Contents
Intro
Sur mon blog, je partage régulièrement mes projets domotiques pour rendre la maison plus confortable et intelligente. Aujourd’hui, je vous présente une de mes automatisations préférées : la gestion générale de mes volets roulants RTS. Ce script, conçu sous Home Assistant, adapte l’ouverture et la fermeture des volets selon les saisons (été/hiver) et mon statut (présent ou absent).
Objectif de l’automatisation
L’idée est simple : automatiser les volets pour qu’ils s’ouvrent et se ferment aux bons moments, en fonction de la luminosité (jour/nuit) et d’horaires prédéfinis pour l’été ou l’hiver. En bonus, un mode « Absent » sécurise la maison quand je ne suis pas là. Cette flexibilité est idéale pour économiser de l’énergie et optimiser le confort.
Les déclencheurs (Triggers)
Mon automatisme repose sur plusieurs déclencheurs pour couvrir tous les cas :
- Changement jour/nuit : Utilisation d’un input_boolean.nuit_jour qui bascule entre « on » (nuit) et « off » (jour). Par exemple, quand on passe de « on » à « off » (nuit vers jour), l’automatisation réagit immédiatement.
- Horaires saisonniers :
- En été : des heures définies via input_datetime.horaire_ete_volet_ouv (ouverture) et input_datetime.horaire_ete_volet_ferm (fermeture).
- En hiver : un horaire spécifique pour l’ouverture avec input_datetime.horaire_hiver_volet_ouv.
Les conditions et actions
Le cœur de l’automatisation repose sur un input_select.volets qui peut être réglé sur trois états : « Auto Hiv » (hiver), « Auto Ete » (été) ou « Absent ». Selon cet état et le déclencheur activé, différentes actions sont exécutées via des scripts :
- Mode Auto Hiver :
- Passage jour -> nuit : fermeture des volets (script).
- Heure d’ouverture hiver : ouverture des volets (script).
- Mode Auto Été :
- Heure d’ouverture été : ouverture des volets (même script d’ouverture).
- Heure de fermeture été : fermeture des volets (script).
- Mode Absent :
- Passage jour -> nuit : fermeture sécurisée (script).
- Passage nuit -> jour : ouverture (script).
Si aucune condition n’est remplie, rien ne se passe (action par défaut vide).
Pourquoi ce système ?
Ce setup est super pratique pour plusieurs raisons :
- Adaptabilité : Les horaires changent selon la saison, ce qui est parfait pour gérer la chaleur en été ou la lumière en hiver.
- Sécurité : Le mode Absent simule une présence en ouvrant et fermant les volets, dissuadant les intrusions.
- Simplicité : Une fois configuré, tout est automatique, et je peux ajuster les horaires via l’interface de Home Assistant.
Mesure de la luminosité : Une détection précise du jour et de la nuit
Pour que le passage jour/nuit soit vraiment intelligent, j’ai ajouté une automatisation dédiée au calcul de l’état input_boolean.nuit_jour. Elle repose sur un capteur de luminosité bh1750. et la position du soleil (sun.sun). Voici comment ça marche :
- Déclencheurs :
- Passage nuit -> jour : déclenché quand la luminosité dépasse un seuil haut (input_number.luminosite_seuil_haut) et que le soleil est au-dessus de l’horizon.
- Passage jour -> nuit : activé quand la luminosité tombe sous un seuil bas (input_number.luminosite_seuil_bas) et que le soleil est sous l’horizon.
- Actions :
- Nuit -> Jour : met input_boolean.nuit_jour sur « on ».
- Jour -> Nuit : met input_boolean.nuit_jour sur « off ».
Le code YAML de cette automatisation :
alias: Calcul Boolean Nuit/Jour
description: ""
triggers:
- value_template: >-
{{ states('sensor.bh1750_illuminance')|float(default=0) >
states('input_number.luminosite_seuil_haut')|float(default=0) and
is_state("sun.sun", "above_horizon") }}
id: nuit->jour
trigger: template
- value_template: >-
{{ states('sensor.bh1750_illuminance')|float(default=0) <
states('input_number.luminosite_seuil_bas')|float(default=0) and
is_state("sun.sun", "below_horizon") }}
id: jour->nuit
trigger: template
actions:
- choose:
- conditions:
- condition: trigger
id: nuit->jour
sequence:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.nuit_jour
- conditions:
- condition: trigger
id: jour->nuit
sequence:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.nuit_jour
default: []
mode: single
Cette approche combine la mesure réelle de la luminosité avec les données astronomiques, rendant la détection hyper fiable, même par temps nuageux ou pluvieux.
Piloter les volets Somfy RTS avec ESPSomfy-RTS
Pour contrôler mes volets Somfy RTS, j’ai opté pour la solution open-source ESPSomfy-RTS, que j’ai découverte sur GitHub (voir ici). Ce projet utilise un ESP32 couplé à un module CC1101 pour envoyer et recevoir des commandes RTS sur la fréquence 433 MHz. Voici pourquoi et comment je l’utilise :
- Matériel abordable : Pour environ 12 €, j’ai assemblé un ESP32 et un CC1101 avec des connecteurs Dupont, sans soudure. C’est simple et accessible.
- Configuration : Après avoir flashé le firmware (disponible dans les releases GitHub), je connecte l’ESP32 à mon réseau Wi-Fi via son interface web (http://192.168.4.1 en mode AP initial). Ensuite, je configure les volets en les associant au système, un peu comme on programme une télécommande Somfy.
- Intégration avec Home Assistant : ESPSomfy-RTS s’intègre nativement à Home Assistant via une découverte automatique ou MQTT. Mes scripts (comme ceux ci-dessus) appellent ensuite les commandes via les entités créées (ex. cover.volet_salon).
- Avantages : Contrairement à une télécommande classique, ESPSomfy-RTS suit la position des volets même quand je les pilote manuellement, et il supporte jusqu’à 32 volets individuels ou 16 groupes. Un vrai plus pour une maison connectée !
Pour plus de détails sur la configuration, consultez le wiki officiel. Avec cette solution, mes volets sont non seulement automatisés, mais aussi accessibles depuis n’importe où via Home Assistant.


Montage de l’ESP32
Afin de fiabiliser mon montage, j’ai opté pour la conception avec EasyEda et la réalisation dun circuit imprimé confié à JLCPCB (5 ex pour une poignée d’€).



Integration dans HA
Le code de l’automatisation principale
Pour les curieux, voici le YAML de l’automatisation des volets:
alias: Volet Automatisme Général RTS
description: "Ete/Hiver/Absent "
triggers:
- entity_id:
- input_boolean.nuit_jour
from: "on"
to: "off"
id: jour->nuit
for:
hours: 0
minutes: 0
seconds: 0
trigger: state
- at: input_datetime.horaire_ete_volet_ouv
id: heure_ouv
trigger: time
- at: input_datetime.horaire_ete_volet_ferm
id: heure_ferm
trigger: time
- entity_id:
- input_boolean.nuit_jour
id: nuit->jour
from: "off"
to: "on"
for:
hours: 0
minutes: 0
seconds: 0
trigger: state
- at: input_datetime.horaire_hiver_volet_ouv
id: ouv_hiv
trigger: time
conditions: []
actions:
- choose:
- conditions:
- condition: state
entity_id: input_select.volets
state: Auto Hiv
- condition: trigger
id: jour->nuit
sequence:
- data: {}
action: script.1706464871250
- conditions:
- condition: state
entity_id: input_select.volets
state: Auto Hiv
- condition: trigger
id:
- ouv_hiv
sequence:
- data: {}
action: script.0_0_1_ouverture_volets_rts
- conditions:
- condition: state
entity_id: input_select.volets
state: Auto Ete
- condition: trigger
id: heure_ouv
sequence:
- data: {}
action: script.0_0_1_ouverture_volets_rts
- conditions:
- condition: state
entity_id: input_select.volets
state: Auto Ete
- condition: trigger
id: heure_ferm
sequence:
- data: {}
action: script.1706464871250
- conditions:
- condition: state
entity_id: input_select.volets
state: Absent
- condition: trigger
id: jour->nuit
sequence:
- data: {}
action: script.0_1_0_fermeture_volets_mode_absent_rts
- conditions:
- condition: state
entity_id: input_select.volets
state: Absent
- condition: trigger
id: nuit->jour
sequence:
- data: {}
action: script.0_1_1_ouverture_volets_mode_absent_rts
default: []
mode: single
Interface Lovelace

type: vertical-stack
cards:
- cards:
- cards:
- entity: cover.porte_garage
label: Garage
operator: default
show_icon: true
show_label: true
show_name: false
size: 70%
state:
- color: green
icon: mdi:garage
operator: template
value: >
[[[ return
states['cover.porte_garage'].attributes.current_position < 1
]]]
- color: red
icon: mdi:garage-open
operator: template
value: >
[[[ return
states['cover.porte_garage'].attributes.current_position > 99
]]]
- color: orange
icon: mdi:garage-alert
operator: default
tap_action:
action: more-info
theme: Mushroom
type: custom:button-card
- icon: mdi:arrow-up-bold
name: Ouvrir
show_icon: true
show_name: false
tap_action:
action: call-service
service: cover.open_cover
service_data: {}
target:
entity_id:
- cover.porte_garage
type: button
- icon: mdi:pause
name: Stop
show_name: false
tap_action:
action: call-service
service: cover.stop_cover
service_data: {}
target:
entity_id:
- cover.porte_garage
type: button
- icon: mdi:arrow-down-bold
name: Fermer
show_name: false
tap_action:
action: call-service
service: cover.close_cover
service_data: {}
target:
entity_id:
- cover.porte_garage
type: button
- icon: mdi:weather-sunset-up
name: Soleil
show_name: false
tap_action:
action: call-service
service: cover.set_cover_position
service_data:
position: 50
target:
entity_id:
- cover.porte_garage
type: button
- elements:
- attribute: current_position
entity: cover.porte_garage
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- entity: cover.porte_sous_sol
label: Sous Sol
show_icon: true
show_label: true
show_name: false
size: 70%
state:
- color: green
icon: mdi:garage
operator: template
value: >
[[[ return
states['cover.porte_sous_sol'].attributes.current_position < 1
]]]
- color: red
icon: mdi:garage-open
operator: template
value: >
[[[ return
states['cover.porte_sous_sol'].attributes.current_position >
99 ]]]
- color: orange
icon: mdi:garage-alert
operator: default
tap_action:
action: more-info
theme: Mushroom
type: custom:button-card
- icon: mdi:arrow-up-bold
name: Ouvrir
show_icon: true
show_name: false
tap_action:
action: call-service
service: cover.open_cover
service_data: {}
target:
entity_id:
- cover.porte_sous_sol
type: button
- icon: mdi:pause
name: Stop
show_name: false
tap_action:
action: call-service
service: cover.stop_cover
service_data: {}
target:
entity_id:
- cover.porte_sous_sol
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id: cover.porte_sous_sol
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.porte_sous_sol
data:
position: 15
type: button
- elements:
- attribute: current_position
entity: cover.porte_sous_sol
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- entity: cover.volet_bureau_rts
hold_action:
action: none
icon: mdi:desk-lamp
name: Bureau
show_icon: true
show_name: true
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volet_bureau_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volet_bureau_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volet_bureau_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volet_bureau_rts
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volet_bureau_rts
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- show_name: true
show_icon: true
entity: cover.volets_salon_rts
hold_action:
action: none
icon: mdi:sofa
name: Salon
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volets_salon_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volets_salon_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volets_salon_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volets_salon_rts
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volets_salon_rts
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- show_name: true
show_icon: true
entity: cover.volet_sdb_rts
hold_action:
action: none
icon: mdi:bathtub
name: SdB
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volet_sdb_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volet_sdb_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volet_sdb_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volet_sdb_rts
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volet_sdb_rts
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- show_name: true
show_icon: true
entity: cover.volet_ch_nord
hold_action:
action: none
icon: mdi:bed
name: A Nord
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volet_ch_nord
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volet_ch_nord
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volet_ch_nord
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volet_ch_nord
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volet_ch_nord
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- show_name: true
show_icon: true
entity: cover.volets_ch_parents_rts
hold_action:
action: none
icon: mdi:bed
name: Parents
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volets_ch_parents_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volets_ch_parents_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volets_ch_parents_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volets_ch_parents_rts
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volets_ch_parents_rts
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
- cards:
- show_name: true
show_icon: true
entity: cover.volets_ch_sud_rts
hold_action:
action: none
icon: mdi:bed
name: A Sud
show_state: false
tap_action:
action: more-info
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-up-bold
name: Ouvrir
tap_action:
action: call-service
service: cover.open_cover
target:
entity_id:
- cover.volets_ch_sud_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:pause
name: Stop
tap_action:
action: call-service
service: cover.stop_cover
target:
entity_id:
- cover.volets_ch_sud_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:arrow-down-bold
name: Fermer
tap_action:
action: call-service
service: cover.close_cover
target:
entity_id:
- cover.volets_ch_sud_rts
data: {}
type: button
- show_name: false
show_icon: true
icon: mdi:weather-sunset-up
name: Soleil
tap_action:
action: call-service
service: cover.set_cover_position
target:
entity_id:
- cover.volets_ch_sud_rts
data:
position: 50
type: button
- elements:
- attribute: current_position
entity: cover.volets_ch_sud_rts
style:
color: "#44739E"
font-size: 16px
font-weight: bold
left: 50%
top: 50%
suffix: "%"
tap_action:
action: more-info
type: state-label
image: /local/images/carre_orange.png
type: picture-elements
view_layout:
position: sidebar
columns: 6
square: true
type: grid
type: vertical-stack
Conclusion
Avec cette automatisation, mes volets RTS sont devenus de vrais alliés au quotidien. Que ce soit pour garder la fraîcheur en été, profiter du soleil d’hiver ou sécuriser la maison en mon absence, tout est géré sans effort. La mesure de luminosité ajoute une précision redoutable, et ESPSomfy-RTS apporte une solution robuste et économique pour piloter mes volets Somfy. Si vous avez des volets compatibles RTS et Home Assistant, je vous encourage à tester cette configuration. Vous avez des idées pour l’améliorer ? Laissez un commentaire sur domo.rem81.com !