In het huis waarin we deze zomer zijn gaan wonen hangt een op afstand bestuurbaar gordijnen systeem. Dit systeem werkt goed en betrouwbaar middels de afstandsbediening die bij het systeem hoort. Het zijn rolgordijnen van Luxaflex welke de techniek van HunterDouglas gebruiken. Over de integratie van dit HunterDouglas systeem is wel wat te vinden op internet, maar er is geen verkrijgbaarheid van de hub. Daarnaast zou het maar de vraag zijn of mijn verouderde versie van het systeem überhaupt zou werken op de hub en of de hub dan weer werkt met Home Assistant. Toch wil ik de gordijnen met Home Assistant kunnen bedienen. Dat werd een uitdaging, maar het is gelukt!
Elimineren van losse afstandsbedieningen
In mijn eerdere artikel Mitsubishi Airco’s toevoegen aan Home Assistant was ik ook al bezig geweest met het verminderen van het gebruik van de losse afstandsbedieningen in ons huis. We hadden er dus één voor de airco, twee voor dit gordijnen systeem en één voor de somfy zonnewering (die is deze zomer aan de beurt!). Door het inbouwen van een ESP in de Mitshibisi Airco was ik al verlost van één afstandsbediening, nu zijn de twee van het Luxaflex systeem aan de beurt.
Hoe voeg je een ouderwetse afstandsbediening toe aan Home Assistant?
Met deze vraag begon mijn zoektocht naar een oplossing. De oplossing die ik als eerste had was het kopiëren van de infrarood codes van de afstandsbediening. Doordat je een infrarood code die de originele afstandsbediening stuurt aanleert aan Home Assistant, kun je via Home Assistant opnieuw het commando versturen. Ik bestelde een Tuya IR sender/receiver voor een paar euro. Het werkt helaas niet zoals verwacht.
Methode 1: aanleren van infrarood code
In de Tuya app kun je mooi de commando’s aanleren die de afstandsbediening stuurt. Door op de knop in de app te drukken kun je die commando’s opnieuw versturen.

Helaas gebeurde er vervolgens niets met het gordijn. Na wat onderzoek bleek dat het protocol dat de afstandsbediening gebruikt niet een standaard protocol is en dat het gebruik maakt van ‘rolling codes’. In rolling codes veranderd er steeds een stukje code en is het een soort van beveiligd. Daarbij komt nog, had het wel gewerkt via de Tuya app, had het nog steeds niet gewerkt via Home Assistant, want de Tuya integratie geeft deze ‘apparaten’ door als ‘unsupported’. Ik moest dus een andere aanpak bedenken.

Methode 2: aanleren van de RF code
De afstandbediening heeft twee manieren om de gordijnen te bedienen. Via infrarood of via RF op 2.4Ghz. Via RF op 2.4Ghz werkt de besturing veel betrouwbaarder dan via IR. Het heeft dus zeker de voorkeur om de aansturing via RF te laten gaan. Na veel zoeken op forums en de rest van het internet kwam ik geen overtuigende resultaten tegen hoe ik dit RF signaal kan reproduceren via ESPHome.
Methode 3: Automatische druk op knop
Het derde idee was eigenlijk heel simpel. Ik hergebruik de afstandbediening en moet gewoon doen alsof er op de knop gedrukt wordt.
Ik heb de afstandsbediening opengemaakt, de binnenkant bekeken en een plan gemaakt.

De afstandsbediening in kwestie heeft 7 knoppen en werkt op twee AAA-batterijen, dus 3V. Onder de rubber knopjes zit een contactje wat hierop reageert. Ik heb wat van het zwarte materiaal weggekrab met een mesje en toen werd het koperbaantje zichtbaar. Door de aparte koperbaantjes door te verbinden aan elkaar simuleerde ik een druk op de knop. Top! Nu moest ik nog een component vinden dat dat voor me kan doen in samenwerking met een ESP.

Optocoupler voor het simuleren van een druk op de knop
Om een druk op de knop te simuleren maak je gebruik van een optocoupler. Door aan de ene kant een stuursignaal op de optocoupler te zetten gaat de andere zijde geleiden en is het net alsof er op de knop gedrukt wordt. Voor mezelf heb ik het volgende simpele schema gemaakt:

Het deel met de optocoupler moet net zo vaak gemaakt worden als dat je knoppen wilt bedienen. In mijn geval dus 7. Dat is ook de reden dat ik heb gekozen voor een ESP32. 7 GPIO’s is net te veel voor een Wemos D1 mini. Om het voor mezelf makkelijk te maken heb ik alle optocouplers op een stukje PCB gesoldeerd. Alle GND’s heb ik met elkaar verbonden (groene draad). Alle pins naar de ESP heb ik met rood draad uitgevoerd. De draden naar de knoppen op de afstandsbediening heb ik voorzien van blauw draad. Let op, dit komt niet helemaal overeen met de kleur draden van de schets. Nu het softwarematige gedeelte nog.

ESPHome gebruiken voor het vervangen van je oude afstandsbediening
Op de Wemos S2 Mini gaan we ESPHome flashen. Voor het uitvoeren van een actie voor mijn gordijnen moet je steeds twee knoppen indrukken. Eerst een cijferknop van het gordijn dat je wilt bedienen. Op de originele afstandsbediening zijn dat de knoppen 1,2,3,4 en ALL. Daarna moet je kiezen of je het gordijn omhoog of omlaag wilt doen. Hiervoor druk je normaal op knop UP of DOWN. Alle afstandsbediening knoppen heb ik in ESPHome nagemaakt door middel van de volgende code:
switch: - platform: gpio pin: 7 id: UP - platform: gpio pin: 5 id: ALL - platform: gpio pin: 9 id: DOWN - platform: gpio pin: 3 id: EEN - platform: gpio pin: 34 id: DRIE - platform: gpio pin: 21 id: TWEE - platform: gpio pin: 17 id: VIER
Om een druk op de knop te simuleren heb ik per knop een script gemaakt in ESPHome. Deze zet de pin voor 0.2 seconden op HIGH en zet ‘m daarna weer op LOW. Zo ‘denkt’ de afstandsbediening dus dat er op de knop gedrukt is, maar dat hebben we dus via ESPHome gedaan!
# Definieer het script dat de sequentie uitvoert script: - id: PRESS_ALL mode: single then: - switch.turn_on: ALL - delay: 0.2s - switch.turn_off: ALL - delay: 0.2s - id: PRESS_DOWN mode: single then: - switch.turn_on: DOWN - delay: 0.2s - switch.turn_off: DOWN - delay: 0.2s - id: PRESS_UP mode: single then: - switch.turn_on: UP - delay: 0.2s - switch.turn_off: UP - delay: 0.2s - id: PRESS_EEN mode: single then: - switch.turn_on: EEN - delay: 0.2s - switch.turn_off: EEN - delay: 0.2s - id: PRESS_TWEE mode: single then: - switch.turn_on: TWEE - delay: 0.2s - switch.turn_off: TWEE - delay: 0.2s - id: PRESS_DRIE mode: single then: - switch.turn_on: DRIE - delay: 0.2s - switch.turn_off: DRIE - delay: 0.2s - id: PRESS_VIER mode: single then: - switch.turn_on: VIER - delay: 0.2s - switch.turn_off: VIER - delay: 0.2s
Nu willen we dit natuurlijk ook via Home Assistant kunnen doen. Dat kan door het maken van buttons. Deze buttons doen zich voor zoals op de afstandsbediening, dus als enkele acties.
# Maak een virtuele knop voor Home Assistant om het script te starten button: - platform: template name: "ALL UP" on_press: then: - script.execute: PRESS_ALL - script.execute: PRESS_UP - platform: template name: "ALL DOWN" on_press: then: - script.execute: PRESS_ALL - script.execute: PRESS_DOWN - platform: template name: "UP" on_press: then: - script.execute: PRESS_UP - platform: template name: "DOWN" on_press: then: - script.execute: PRESS_DOWN - platform: template name: "EEN" on_press: then: - script.execute: PRESS_EEN - platform: template name: "TWEE" on_press: then: - script.execute: PRESS_TWEE - platform: template name: "DRIE" on_press: then: - script.execute: PRESS_DRIE - platform: template name: "VIER" on_press: then: - script.execute: PRESS_VIER

Gordijnen toevoegen aan Home Assistant
Maar het allermooiste is het om je gordijnen via een cover entity te bedienen! Je krijgt in Home Assistant daarmee ook andere ondersteunde acties zoals het draaien (tilt) van de rolgordijnen wat die van mij ook ondersteunen. Dit is wel wat meer tricky, omdat er vanuit de gordijnen geen terugkoppeling is van hoe ze staan. Dit probeer ik op te vangen door per gordijn een global variabele op te slaan wat de laatste actie was. Over het algemeen werkt het wel goed, maar als de batterijen van de gordijnen leeg raken willen ze nog wel eens een commando missen en uit sync raken. Kun je handmatig wel weer oplossen. Door onderstaande code maak je per gordijn een cover aan met de juiste commando’s en globals. Wanneer Home Assistant de open actie verstuurt, voert ESPHome de acties uit onder ‘open_action’.
globals: - id: laatste_richting_1 type: std::string initial_value: '"stop"' - id: laatste_richting_2 type: std::string initial_value: '"stop"' - id: laatste_richting_3 type: std::string initial_value: '"stop"' - id: laatste_richting_4 type: std::string initial_value: '"stop"' cover: - platform: template id: cover_een name: Gordijn Werkkamer assumed_state: true device_class: blind open_action: then: - lambda: |- id(laatste_richting_1) = "open"; - script.execute: PRESS_EEN - script.execute: PRESS_UP close_action: then: - lambda: |- id(laatste_richting_1) = "close"; - script.execute: PRESS_EEN - script.execute: PRESS_DOWN tilt_action: then: - if: condition: lambda: 'return id(laatste_richting_1) == "close";' then: # Wanneer het grodijn dicht is en je wilt tilten, moet je naar beneden drukken - script.execute: PRESS_EEN - script.execute: PRESS_DOWN - lambda: |- id(laatste_richting_1) = "tilt_open"; - if: condition: lambda: 'return id(laatste_richting_1) == "tilt_open";' then: - script.execute: PRESS_EEN - script.execute: PRESS_UP - lambda: |- id(laatste_richting_1) = "close"; stop_action: then: - if: condition: lambda: 'return id(laatste_richting_1) == "open";' then: - script.execute: PRESS_EEN - script.execute: PRESS_DOWN - if: condition: lambda: 'return id(laatste_richting_1) == "close";' then: - script.execute: PRESS_EEN - script.execute: PRESS_UP - lambda: |- id(laatste_richting_1) = "stop"; ############################################################ - platform: template id: cover_twee name: Gordijn Woonkamer assumed_state: true device_class: blind open_action: then: - lambda: |- id(laatste_richting_2) = "open"; - script.execute: PRESS_TWEE - script.execute: PRESS_UP close_action: then: - lambda: |- id(laatste_richting_2) = "close"; - script.execute: PRESS_TWEE - script.execute: PRESS_DOWN tilt_action: then: - if: condition: lambda: 'return id(laatste_richting_2) == "close";' then: # Wanneer het grodijn dicht is en je wilt tilten, moet je naar beneden drukken - script.execute: PRESS_TWEE - script.execute: PRESS_DOWN - lambda: |- id(laatste_richting_2) = "tilt_open"; - if: condition: lambda: 'return id(laatste_richting_2) == "tilt_open";' then: - script.execute: PRESS_TWEE - script.execute: PRESS_UP - lambda: |- id(laatste_richting_2) = "close"; stop_action: then: - if: condition: lambda: 'return id(laatste_richting_2) == "open";' then: - script.execute: PRESS_TWEE - script.execute: PRESS_DOWN - if: condition: lambda: 'return id(laatste_richting_2) == "close";' then: - script.execute: PRESS_TWEE - script.execute: PRESS_UP - lambda: |- id(laatste_richting_2) = "stop"; ################################################ - platform: template id: cover_DRIE name: Gordijn Garage assumed_state: true device_class: blind open_action: then: - lambda: |- id(laatste_richting_3) = "open"; - script.execute: PRESS_DRIE - script.execute: PRESS_UP close_action: then: - lambda: |- id(laatste_richting_3) = "close"; - script.execute: PRESS_DRIE - script.execute: PRESS_DOWN tilt_action: then: - if: condition: lambda: 'return id(laatste_richting_3) == "close";' then: # Wanneer het grodijn dicht is en je wilt tilten, moet je naar beneden drukken - script.execute: PRESS_DRIE - script.execute: PRESS_DOWN - lambda: |- id(laatste_richting_3) = "tilt_open"; - if: condition: lambda: 'return id(laatste_richting_3) == "tilt_open";' then: - script.execute: PRESS_DRIE - script.execute: PRESS_UP - lambda: |- id(laatste_richting_3) = "close"; stop_action: then: - if: condition: lambda: 'return id(laatste_richting_3) == "open";' then: - script.execute: PRESS_DRIE - script.execute: PRESS_DOWN - if: condition: lambda: 'return id(laatste_richting_3) == "close";' then: - script.execute: PRESS_DRIE - script.execute: PRESS_UP - lambda: |- id(laatste_richting_3) = "stop"; ####################################################### - platform: template id: cover_VIER name: Gordijn Achterdeur assumed_state: true device_class: blind open_action: then: - lambda: |- id(laatste_richting_4) = "open"; - script.execute: PRESS_VIER - script.execute: PRESS_UP close_action: then: - lambda: |- id(laatste_richting_4) = "close"; - script.execute: PRESS_VIER - script.execute: PRESS_DOWN tilt_action: then: - if: condition: lambda: 'return id(laatste_richting_4) == "close";' then: # Wanneer het grodijn dicht is en je wilt tilten, moet je naar beneden drukken - script.execute: PRESS_VIER - script.execute: PRESS_DOWN - lambda: |- id(laatste_richting_4) = "tilt_open"; - if: condition: lambda: 'return id(laatste_richting_4) == "tilt_open";' then: - script.execute: PRESS_VIER - script.execute: PRESS_UP - lambda: |- id(laatste_richting_4) = "close"; stop_action: then: - if: condition: lambda: 'return id(laatste_richting_4) == "open";' then: - script.execute: PRESS_VIER - script.execute: PRESS_DOWN - if: condition: lambda: 'return id(laatste_richting_4) == "close";' then: - script.execute: PRESS_VIER - script.execute: PRESS_UP - lambda: |- id(laatste_richting_4) = "stop"; ########################################
In Home Assistant ziet dat er dan vervolgens zo uit op je dashboard:

De status van het gordijn wordt over het algemeen juist weergegeven door de entiteiten doordat assumed_state op true staat. Deze communiceert de laatste actie naar Home Assistant zodat het de status van het gordijn kan weergeven. Zoals ik al eerder scheef kan het zo zijn dat de gordijnen uit sync raken door bijna lege batterijen. Ze missen dan wel eens een commando.
Het werkt!
Door het vervangen van de oude afstandsbediening voor een ESP32 met ESPHome ben ik verlost van twee losse afstandsbedieningen. De zelfgemaakte afstandsbediening in Home Assistant werkt perfect en betrouwbaar. Ik heb geen reden om de oude afstandbediening nog te gebruiken. De implementatie van de gordijnen in Home Assistant via de cover enties van esphome is erg uitgebreid en werkt zoals je verwacht. Missie geslaagd!
Van welk apparaat heb jij een oude ouderwetse afstandbediening die je wilt gebruiken met Home Assistant? Laat het weten in de comments!
Goed gevonden! Inspireert de HA Community om ook soortgelijke oplossingen te vinden.
Leuk gemaakt,
Heb hem ook weer gedeeld binnen de huizebruin Discord groep met ruim 250+ gebruikers van ondermeer home assistant en esphome en elektronica en 3D print en meer.
https://discord.gg/kBCExzFq