Home Assistant et les télécommandes
Pour gérer les télécommandes, j'utilise depuis des années ControllerX qui tourne sous AppDaemon, c'est simple, et ça fonctionne très bien. Problème, s'il en est, d'une part je suis perplexe sur l'avenir de cette solution, et d'autre part je me dis que simplifier et avoir le moins d'addons possible c'est toujours mieux.
En alternative à ControllerX il existe la solution BluePrint. C'est bien et j'en utilise plusieurs, dont certains sont de véritables usines à gaz. C'est parfois utile pour certaines taches complexes pour lesquelles je n'ai pas envie de mes farcir des heures de YAML.
Avec ControllerX je gérait les télécommandes Ikea associés aux Shelley 2.5 de mes volets roulants, c'est simple et ça fonctionne depuis des années :
volet_rc_ikea_07:
module: controllerx
class: E1743CoverController
controller: bc:33:ac:ff:fe:be:50:21
integration: zha
cover: cover.vr_baiePour remplacer ça j'ai d'abord testé plusieurs BluePrint dédié aux diverses télécommandes, et ça foisonne. Mais aucun ne faisais exactement ce que ControllerX fait, à savoir, exploiter les deux boutons et faire un stop avec un clic supplémentaire. Et puis je me suis dit que je devrais pouvoir gérer tout seul toutes les télécommandes de tous mes volets avec une seule automation, que ça serait plus simple, et donc plus réactif.
Pour chaque télécommande on va exploiter un trigger: qui correspond à l'action de la télécommande (simple ON, double OFF, etc...). Dans ce trigger on y colle un id: baie_on ou la première partie correspond au nom du volet et la seconde à l'action.
Ensuite on s'en sert pour gérer des variables qui correspondent au volet et on exploite ça dans un choose: qui va tester si le volet est en mouvement pour faire un cover.stop_cover et se servir de la seconde partie du trigger.id pour le faire monter ou le descendre.
Avec cette solution il est dans l'absolu possible de gérer un nombre infini de volets et de télécommandes, voire même de gérer autre chose que des volets... Et bien sur les télécommandes peuvent provenir de différentes intégrations (ici Z2M et ZHA).
alias: Remote Covers - Multiples & Stop
description: Gère plusieurs volets et plusieurs télécommandes indépendamment avec fonction Stop
triggers:
- domain: mqtt
device_id: 1a4ba8e9b8e66a574e3c688f907e70fd
type: action
subtype: "on"
id: lionel_on
trigger: device
- domain: mqtt
device_id: 1a4ba8e9b8e66a574e3c688f907e70fd
type: action
subtype: "off"
id: lionel_off
trigger: device
- device_id: c3c2106f2d457bc86c573fed853f02fc
domain: zha
type: remote_button_short_press
subtype: turn_on
id: marie_on
trigger: device
- device_id: c3c2106f2d457bc86c573fed853f02fc
domain: zha
type: remote_button_short_press
subtype: turn_off
id: marie_off
trigger: device
actions:
- variables:
target_cover: >
{% if trigger.id.startswith('lionel') %} cover.vr_lionel
{% elif trigger.id.startswith('marie') %} cover.vr_marie
{% elif trigger.id.startswith('autre') %} cover.vr_autre
{% endif %}
- choose:
- conditions:
- condition: template
value_template: >-
{{ is_state(target_cover, 'opening') or
is_state(target_cover, 'closing') }}
sequence:
- action: cover.stop_cover
target:
entity_id: "{{ target_cover }}"
- conditions:
- condition: template
value_template: "{{ trigger.id.endswith('_on') }}"
sequence:
- action: cover.open_cover
target:
entity_id: "{{ target_cover }}"
- conditions:
- condition: template
value_template: "{{ trigger.id.endswith('_off') }}"
sequence:
- action: cover.close_cover
target:
entity_id: "{{ target_cover }}"
mode: restart
max_exceeded: silent
Et sans Home Assistant ?
Tout ça c'est génial, je pose une télécommande (Zigbee, Matter ou ce qu'on veut Home Assistant gère tout ça comme vu précédemment. Sauf que je n'ai pas de boutons filaires sous les volets, donc si Home Assistant plante, ou si je ne suis pas (ou plus) là pour maintenir ce bazard, c'est le bug !
Les Shelly 2.5 qui gèrent mes volets sont au tableau et il y a là, en secours, des poussoirs qui permettent de les manipuler. Pas très pratique ! Le jour ou je remplacerait les Shelly 2.5 pour un modèle plus récent, je pourrais y associer des télécommandes en lien direct (Bluetooth ou mieux en Zigbee avec un bonding sur le cluster Window Covering.
En attendant je vais me servir s'un Shelly gen2 qui me servira de passerelle BT et utiliser la méthode officielle BTHome v2 ! (Merci l'IA...) Le décodage par paires de type 0x3A est la façon la plus propre et robuste de lire les données envoyées par les périphériques Shelly BLU.
Voici le récapitulatif complet de ce que fait ce script pour tes 4 volets :
- Décodage direct BTHome (
0x3A) : Il parcourt directement la trame à la recherche des identifiants de boutons sans dépendre d'un décalage de texte Base64 instable. - Identification des boutons (1 à 4) : Il incrémente le numéro de bouton dans l'ordre où BTHome les transmet.
- Gestion des événements :
1(Clic simple) : Alternance entre OPEN et STOP. Si le script sait que le volet a été lancé (openingouclosing), le clic court suivant envoie un STOP. Sinon, il lance un OPEN.4(Appui long) : Envoie directement l'ordre CLOSE (et met à jour l'état interne pour que le prochain clic court fasse un STOP pour interrompre la descente).
- Anti-doublon matériel : Il utilise le compteur
packetIdnatif du BTHome v2 pour ignorer automatiquement les répétitions radio sans bloquer les commandes légitimes.
// === CONFIGURATION ===
let MAC_TELECOMMANDE = "7c:c6:b6:ac:85:44";
// IP de tes 4 Shelly 2.5 (Mode Cover / Volet)
let VOLETS = {
1: "192.168.1.51", // Bouton 1
2: "192.168.1.52", // Bouton 2
3: "192.168.1.53", // Bouton 3
4: "192.168.1.54" // Bouton 4
};
// Mémoire d'état pour alterner : OPEN -> STOP ou CLOSE -> STOP
let ETAT_VOLET = { 1: "stopped", 2: "stopped", 3: "stopped", 4: "stopped" };
// Anti-doublon basé sur le compteur de paquet BTHome
let LAST_PACKET_ID = -1;
function b64decode(s) {
let b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", o1, o2, o3, h1, h2, h3, h4, bits, i = 0, d = "";
if (!s) return "";
do {
h1 = b.indexOf(s.charAt(i++));
h2 = b.indexOf(s.charAt(i++));
h3 = b.indexOf(s.charAt(i++));
h4 = b.indexOf(s.charAt(i++));
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
o1 = bits >> 16 & 0xff;
o2 = bits >> 8 & 0xff;
o3 = bits & 0xff;
if (h3 === 64) d += String.fromCharCode(o1);
else if (h4 === 64) d += String.fromCharCode(o1, o2);
else d += String.fromCharCode(o1, o2, o3);
} while (i < s.length);
return d;
}
Shelly.addEventHandler(function (ev) {
if (!ev || !ev.info || ev.info.event !== "ble.scan_result" || !ev.info.data || !ev.info.data[1]) return;
let devs = ev.info.data[1];
for (let i = 0; i < devs.length; i++) {
let dev = devs[i];
if (dev[0].toLowerCase() !== MAC_TELECOMMANDE.toLowerCase()) continue;
let raw = b64decode(dev[2]);
if (raw.length < 10) continue;
// Paquet BTHome v2 : l'index 8/9 contient le Packet ID
let packetId = raw.charCodeAt(8) | (raw.charCodeAt(9) << 8);
if (packetId === LAST_PACKET_ID) continue;
// Analyse des paires TLV (Type-Length-Value) BTHome
let idx = 10;
let buttonNum = 0;
let btnFound = 0;
let eventType = 0;
while (idx < raw.length - 1) {
let sensorId = raw.charCodeAt(idx);
// ID 0x3A (58 en décimal) = Bouton BTHome v2
if (sensorId === 0x3A) {
buttonNum++;
let val = raw.charCodeAt(idx + 1);
if (val !== 0) { // Un événement est présent sur ce bouton
btnFound = buttonNum;
eventType = val; // 1 = Single Push, 4 = Long Push
break;
}
idx += 2;
} else {
idx++;
}
}
if (btnFound === 0 || eventType === 0) continue;
// Validation du paquet unique
LAST_PACKET_ID = packetId;
let ip = VOLETS[btnFound];
let action = "";
// Appui Long (4) = CLOSE
if (eventType === 4) {
action = "close";
ETAT_VOLET[btnFound] = "closing";
}
// Clic Simple (1) = OPEN ou STOP
else if (eventType === 1) {
if (ETAT_VOLET[btnFound] === "opening" || ETAT_VOLET[btnFound] === "closing") {
action = "stop";
ETAT_VOLET[btnFound] = "stopped";
} else {
action = "open";
ETAT_VOLET[btnFound] = "opening";
}
}
if (action !== "") {
let url = "http://" + ip + "/roller/0?go=" + action;
print("BTHome OK -> Bouton " + btnFound + " (Evt: " + eventType + ") => " + url);
Shelly.call("HTTP.GET", { url: url });
}
}
});Gemini a pris son temps, j'avoue ne pas tout avoir compris, mais un fait est que ça fonctionne. J'ai utilisé une télécommande Shelly RC Button 4, mais ça doit être transposable à d'autres modèles Shelly.
BTHome OK -> Bouton 1 (Evt: 1) => http://192.168.1.51/roller/0?go=open
BTHome OK -> Bouton 1 (Evt: 1) => http://192.168.1.51/roller/0?go=stop
BTHome OK -> Bouton 1 (Evt: 4) => http://192.168.1.51/roller/0?go=close
BTHome OK -> Bouton 1 (Evt: 1) => http://192.168.1.51/roller/0?go=stopPS1 : ne pas oublier de fixer les IP des Shelly 2.5 et de valider l'infra WI-FI. On peut configurer le module qui sert de passerelle en AP de secours et ainsi créer un vase clos. Pas testé.
PS2 : On doit pouvoir associer une télécommande à plusieurs micro modules gen2 et +, dans ce vas il faudra dupliquer le script.