Egyedi ablaknyitás-érzékelő a klímához

Egyedi ablaknyitás-érzékelő a klímához

Előző bejegyzéseimben az itthoni hálózatom építését mutattam be, azonban most tennék egy kis kitérőt, és a legfrissebb projektemet ismertetném veletek. A téma ezúttal nem is igazán hálózatos, sokkal inkább az IoT (Internet of Things) világa.

Jelenleg egy házfelújítás közepén vagyunk, ahol a festés és a villanyszerelés mellett a fűtéskorszerűsítés is zajlik, ami egy nagyobb teljesítményű klímaberendezés beépítését jelenti. A távlati terv az, hogy ez a ház egyfajta vendégházként fog funkcionálni.

Azonban közismert vendéglátós tapasztalat, hogy a szobák lakói nem igazán figyelnek arra, hogy ha a klímaberendezés üzemel, akkor ne tárják ki az ablakot. Illetve arra sem, hogy kikapcsolják a gépet, ha szellőztetnek. Amikor azon gondolkodtam, hogyan oldjam meg ezt a problémát, két lehetőség jutott eszembe:

  • Egyszerűen lekapcsolom a klíma tápellátását egy kontaktorral (mágneskapcsolóval), amit az elosztótáblában helyezek el.
  • Valahogy szoftveresen oldom meg a lekapcsolást.

Nagyon sokáig az első változatot preferáltam, de aztán végiggondoltam a gyakorlati működést. Mi van akkor, ha a vendégek sűrűn nyitogatják az ajtót, vagy ha a huzat csapkodja az ablakot? Ilyenkor a mágneskapcsoló folyamatosan ki-be kapcsolgatná a gépet, ami totálisan egészségtelen a kompresszornak.

Oké, gondoltam, mi lenne, ha egy időzítő relével oldanám meg? Nyitást érzékelek, egy segédrelé behúz, indít egy időzítőt, ami vár körülbelül 1 percet, és csak ezután kapcsolja le a tápfeszültséget. Na de mi van visszazáráskor? Oké, akkor használjunk impulzusrelét időzítővel – futott át az agyamon a következő gondolat.

Ha ezt a vonalat végiggondoljuk, a rendszer egyrészt feleslegesen bonyolulttá válik, másrészt ezek a moduláris készülékek már elég drágák. Csak a kontaktor, az időzítő és a segédrelé ára önmagában meghaladja a 20 000 Ft-ot. És a legnagyobb probléma még mindig fent áll: a klíma drasztikus, szabálytalan leállítása (az áram elvétele), amit a gép elektronikája és kompresszora hosszú távon biztosan nem tolerálna.

Így szépen lassan elkezdtem egy sokkal olcsóbb és „szoftveres” megoldáson gondolkodni. Arra jutottam, hogy a Home Assistant fogja végezni a klíma intelligens menedzselését, és nekem csak egy olyan érzékelőcsoportra van szükségem, ami jelzi a rendszernek, hogy az ablakok és az ajtók éppen nyitva vagy zárva vannak. Home Assistantban ezt a logikát leprogramozni már gyerekjáték.

A történethez hozzátartozik, hogy amikor a ház vezetékelését készítettem, még az első (kontaktoros) verziót terveztem megvalósítani. Emiatt az összes ablaknyitó mágneses szenzort sorba kötöttem, és a vezeték végét közvetlenül az elosztótáblába húztam be. Mielőtt még fognád a fejed a kontaktort természetesen nem közvetlenül a nyitásérzékelőkön keresztül akartam vezérelni. Ezeknek az apró reed érintkezőknek még egy kisebb segédrelé induktív tekercse is túl nagy kapcsolási igénybevételt jelenthet, és megfelelő védelem nélkül idővel beégetheti vagy összehegesztheti őket. Emellett hálózati feszültséget sem akartam az ablakokhoz vezető érzékelőkörre vinni. A reedek ezért csak egy kisfeszültségű és kisáramú vezérlőjelet adtak volna egy galvanikusan leválasztott szilárdtestrelének, amely már a kontaktort vezérelte volna.

Mivel a fizikai vezetékelés már eleve megvolt az elosztóig, egyértelmű volt, hogy egy Home Assistantba integrálható célhardverrel kell megoldanom a feladatot. Nagyon szeretem az egyedi építésű berendezéseket, korábban is többször építettem már Wemos D1 mini segítségével különféle hardvereket, amiket ESPHome-mal integráltam a rendszerbe. Ebben a platformban az a zseniális, hogy natívan és stabilan támogat számtalan szenzort, nyomógombot, kijelzőt és bemenetet.

Építettem már magamnak korábban:

  • Elektromos robogó akkumulátor-töltés felügyeletet (IoT okostöltőt)
  • Konyhai kijelzőt, amin különféle szenzorok adatai jelennek meg
  • Digitális vízszintmérőt

Minthogy gyakran építek magamnak célhardvereket, így mindig van itthon raktáron Wemos D1 mini. Amit kifejezetten szeretek hozzájuk tápegységként használni, az a Hi-Link 5V-os paneltápegysége (HLK-PM01), így az áramellátás kérdése is gyorsan megoldódott.

Ahhoz viszont, hogy ezt a berendezést szabályosan és biztonságosan berakhassam a kismegszakítók mellé az elosztótáblába, a modulnak meg kell felelnie a szigorú érintésvédelmi és mechanikai követelményeknek. Szerencsére ma már könnyen beszerezhető olyan szabványos, DIN sínre pattintható műanyag doboz, amibe behelyezve az egyedi áramkört, a kis készülék azonnal szabályosan beépíthetővé válik.

Ezekből az alkatrészekből fog összeállni az érzékelő

Az összeállított készülék

A Kész „termék”

Ahogy a képeken látható, a rendszer nagyon kevés alkatrészből összeállítható. Az egészet egy próbanyákból álló alaplapra raktam össze, mert ez adja meg a szükséges mechanikai stabilitást. Így teljesen kizárható, hogy az erősáramú (230V) rész véletlenül hozzáérjen a gyengeáramú (5V) körhöz, ami ugye katasztrófát okozna a hálózaton.

Továbbá beépítettem egy kis panel-biztosítékot is a tápegység 230V-os bemenete elé. Első körben egy 125 mA-es biztosítékot raktam bele, de az az indítási áramtüske miatt sajnos kevésnek bizonyult (kiolvadt). Így végül egy 500 mA-es darabot szereltem be helyette. És hogy miért pont 500 mA-est? Mert ez volt otthon a fiókban.

A hardver ezzel elkészült, stabilan ül a DIN sínre pattintva a kismegszakítók mellett.


A nyitásérzékelők bekötése

Mielőtt rátérnék a szoftveres megvalósításra, érdemes megnézni, pontosan mit és hova kötöttem a Wemos D1 minin. A kapcsolási rajz abban is segít, hogy később érthető legyen, miért éppen az adott beállítások szerepelnek az ESPHome konfigurációjában.

Mind a konfigurációban, mind a kapcsolási rajzon látható, hogy az érzékelőkör a Wemos D1 jelölésű lábához csatlakozik, amely az ESP8266 esetében a GPIO5 portnak felel meg. Erre a célra több szabad digitális bemenet is használható lenne, én azonban azért választottam a D1-et, mert egyszerű digitális bemenetként jól használható, és nincs olyan speciális szerepe az ESP8266 rendszerindításában, mint például a D3, D4 vagy D8 lábaknak.

A kapcsolásban a Wemos belső felhúzóellenállása helyett egy külső, 10 kΩ-os ellenállást használok. Ez határozottabb logikai szintet biztosít, ami a nyílászárókhoz vezető, viszonylag hosszú kábelezés mellett kevésbé érzékeny a zavarokra és a bizonytalan bemeneti állapotokra.

Amíg az összes ablak zárva van, a sorba kötött reed érzékelők a D1 bemenetet a GND-re húzzák, ezért azon alacsony, vagyis LOW logikai szint jelenik meg. Ha bármelyik ablakot kinyitják, a soros áramkör megszakad, a 10 kΩ-os ellenállás pedig a bemenetet 3,3 voltra, vagyis HIGH szintre húzza.

A soros kialakítás további előnye, hogy egy vezetékszakadás vagy kilazult csatlakozás ugyanúgy nyitott állapotot eredményez. A rendszer ilyenkor nem tekinti tévesen zártnak az ablakokat, hanem hibabiztos irányba mozdul el, és nyitást jelez.

A megoldás hátránya, hogy az egyetlen közös bemenet miatt nem lehet megállapítani, pontosan melyik ablakot nyitották ki. Ehhez a feladathoz azonban erre nincs is szükség: számomra csak az a fontos, hogy valamennyi nyílászáró zárva van-e.

A firmware feltöltése

A hardver elkészítése után fel kellett töltenem a Wemosra az ESPHome által elkészített firmware-t. Az első telepítéshez USB-kapcsolatra van szükség, ezért a modult egy adatátvitelre is alkalmas micro-USB-kábellel csatlakoztattam a Home Assistantot futtató géphez.

A Home Assistantban megnyitottam az ESPHome Device Builder felületét, létrehoztam az új eszközt, majd bemásoltam a saját konfigurációmat. Az Install lehetőség kiválasztása után az ESPHome ellenőrzi a YAML-fájlt, lefordítja a firmware-t, majd felajánlja a csatlakoztatott soros eszközt a feltöltéshez.

Az első sikeres telepítés után a Wemos újraindul, és a konfigurációban megadott adatokkal csatlakozik a Wi-Fi-hálózathoz. Ettől kezdve a további módosítások már vezeték nélkül, OTA-frissítés segítségével is feltölthetők, így a DIN-sínes dobozba épített készüléket nem kell minden változtatásnál kiszerelni.

# Board: Wemos D1 Mini (ESP8266)

esphome:
  name: ablaknyito-szenzor
  friendly_name: "Ablaknyitó szenzor"

esp8266:
  board: d1_mini

logger:

api:
  encryption:
    key: "IDE_KERUL_A_SAJAT_GENERALT_API_KULCS"

ota:
  - platform: esphome

wifi:
  ssid: "SAJAT_WIFI_HALÓZAT"
  password: "SAJAT_WIFI_JELSZO"

  ap:
    ssid: "Ablaknyitó szenzor Fallback Hotspot"
    password: "SAJAT_FALLBACK_JELSZO"

  # Példaértékek – a saját hálózatnak megfelelően módosítandók
  manual_ip:
    static_ip: 192.168.10.50
    gateway: 192.168.10.1
    subnet: 255.255.255.0
    dns1: 192.168.10.1

captive_portal:

binary_sensor:
  - platform: gpio
    name: "Vendégház ablakok"
    id: vendeghaz_ablakok
    device_class: window

    pin:
      number: D1
      mode:
        input: true

    filters:
      - delayed_on: 500ms
      - delayed_off: 500ms

A klíma vezérlése

Miután az ablaknyitás-érzékelő megjelent a Home Assistantban, már csak azt kellett eldöntenem, hogyan reagáljon a rendszer a nyitott ablakra.

Az eredeti elképzelés szerint ilyenkor egyszerűen kikapcsoltam volna a klímaberendezést, a gondolatmenetet azonban kissé továbbvittem. A teljes leállítás helyett a klímát ventilátor üzemmódba kapcsolom, és egyúttal visszaveszem a ventilátor fordulatszámát.

Ennek az az előnye, hogy a kompresszor leáll, tehát a készülék nem próbálja tovább hűteni vagy fűteni a nyitott ablakon keresztül a külvilágot, a beltéri egység azonban látszólag tovább működik. Így jó eséllyel a vendégnek fel sem tűnik, hogy a rendszer beavatkozott.

Üzemeltetési területen dolgozva azt tapasztaltam, hogy a felhasználók a legkülönfélébb módokon reagálhatnak egy számukra váratlan helyzetre. Ha a klíma hirtelen teljesen kikapcsolna, könnyen azt gondolhatnák, hogy meghibásodott, majd elkezdenék nyomogatni a távirányítót vagy kísérletezni a beállításokkal.

Ventilátor üzemmódban a változás kevésbé feltűnő. A klíma ugyan egy rövid sípolással jelzi az üzemmódváltást, ezzel nem tudok mit kezdeni, de a készülék legalább nem tűnik teljesen működésképtelennek. Reményeim szerint ezzel nem hozom zavarba a felhasználót, és nem késztetem arra, hogy megpróbálja „megjavítani” a rendszert.

A következő Home Assistant-automatizálást teljes egészében mesterséges intelligencia segítségével készítettem. Ennek meglehetősen egyszerű oka van: kifejezetten utálok YAML-ban programozni. Nem maga a vezérlési logika zavar, hanem a YAML kötött szerkezete, a behúzások jelentősége és az, hogy egy rossz helyre került szóköz vagy apró szintaktikai hiba miatt az egyébként helyes gondolatmenet sem működik. Ha ezt a munkát egy erre alkalmas eszköz gyorsabban és kevesebb bosszúsággal elvégzi, nem látom értelmét annak, hogy órákon keresztül én szenvedjek vele.

Az automatizmus elkészítéséhez megadtam a mesterséges intelligenciának a klímaberendezés és az ESPHome-mal létrehozott ablaknyitás-érzékelő Home Assistant-entitását, valamint leírtam az elvárt működést és a kezelendő kivételeket.

Ha valamelyik ablak legalább tíz másodpercig nyitva marad, miközben a klíma hűtés, fűtés, párátlanítás vagy automata üzemmódban működik, az automatizmus először elmenti a készülék aktuális beállításait. Ezek közé tartozik az üzemmód, a célhőmérséklet, a ventilátorfokozat, a kiválasztott preset és a légterelés állapota. Ezután a klímát ventilátor üzemmódba kapcsolja, a ventilátor fordulatszámát pedig alacsony fokozatra állítja.

Amíg az ablak nyitva van, az automatizmus folyamatosan figyeli a klíma állapotát. Ha valaki a távirányítóval ismét hűtésre, fűtésre, párátlanításra vagy automata üzemmódra kapcsolja, a rendszer visszaállítja a készüléket ventilátor módba. Azt sem engedi, hogy ebben az állapotban magasabbra állítsák a ventilátor fordulatszámát: az ilyen módosítást szintén felülírja, és visszaállítja az alacsony fokozatot.

A kézi kikapcsolást ugyanakkor elfogadja. Ha valaki nyitott ablak mellett kikapcsolja a klímát, az automatizmus befejezi a futását, és az ablak későbbi bezárásakor sem indítja újra önállóan a készüléket.

Ha az összes ablak legalább harminc másodpercig zárva marad, és a klíma továbbra is az automatizmus által beállított ventilátor üzemmódban működik, a rendszer visszaállítja a nyitás előtt elmentett állapotot. Először az eredeti üzemmódot tölti vissza, majd a célhőmérsékletet, a ventilátorfokozatot, a presetet és a légterelés beállítását.

A mesterséges intelligencia tehát ebben az esetben a YAML-kód elkészítését végezte el. A működési elvet, az elvárt viselkedést és a kivételkezelést én határoztam meg, az elkészült automatizmust pedig a valódi berendezésen, különböző állapotok előidézésével teszteltem végig.

alias: Midea klíma - ablaknyitás kezelése-V2
description: >-
  Nyitott ablaknál ventilátor módra vált. Bezárás után visszaállítja
  a klíma eredeti beállításait. Nyitott ablaknál nem engedi aktív
  üzemmódban működtetni, és alacsony ventilátorfokozatot tart fenn.
  A kézi kikapcsolást elfogadja.
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.ablaknyito_szenzor_vendeghaz_ablakok
    from: 'off'
    to: 'on'
    for:
      seconds: 10
conditions:
  - condition: template
    value_template: |-
      {{
        states('climate.midea_ac_153931629743881')
        in ['cool', 'heat', 'dry', 'auto']
      }}
actions:
  - variables:
      eredeti_mod: '{{ states(''climate.midea_ac_153931629743881'') }}'
      eredeti_homerseklet: |-
        {{
          state_attr(
            'climate.midea_ac_153931629743881',
            'temperature'
          )
        }}
      eredeti_ventilator: |-
        {{
          state_attr(
            'climate.midea_ac_153931629743881',
            'fan_mode'
          )
        }}
      eredeti_preset: |-
        {{
          state_attr(
            'climate.midea_ac_153931629743881',
            'preset_mode'
          )
        }}
      eredeti_lenges: |-
        {{
          state_attr(
            'climate.midea_ac_153931629743881',
            'swing_mode'
          )
        }}
  - action: climate.set_hvac_mode
    target:
      entity_id: climate.midea_ac_153931629743881
    data:
      hvac_mode: fan_only
  - delay:
      seconds: 1
  - action: climate.set_fan_mode
    target:
      entity_id: climate.midea_ac_153931629743881
    data:
      fan_mode: low
  - repeat:
      while:
        - condition: state
          entity_id: binary_sensor.ablaknyito_szenzor_vendeghaz_ablakok
          state: 'on'
        - condition: template
          value_template: |-
            {{
              states('climate.midea_ac_153931629743881')
              != 'off'
            }}
      sequence:
        - wait_for_trigger:
            - trigger: state
              entity_id:
                - binary_sensor.ablaknyito_szenzor_vendeghaz_ablakok
              from: 'on'
              to: 'off'
              for:
                seconds: 30
              id: ablak_bezarva
            - trigger: state
              entity_id:
                - climate.midea_ac_153931629743881
              to: 'off'
              id: kezzel_kikapcsolva
            - trigger: template
              value_template: |-
                {{
                  states('climate.midea_ac_153931629743881')
                  in ['cool', 'heat', 'dry', 'auto']
                }}
              id: aktiv_mod_beallitva
            - trigger: template
              value_template: |-
                {{
                  states('climate.midea_ac_153931629743881')
                    == 'fan_only'
                  and
                  state_attr(
                    'climate.midea_ac_153931629743881',
                    'fan_mode'
                  ) != 'low'
                }}
              id: ventilator_modositva
        - choose:
            - conditions:
                - condition: template
                  value_template: |-
                    {{
                      wait.trigger is not none
                      and wait.trigger.id
                        in ['aktiv_mod_beallitva', 'ventilator_modositva']
                      and
                      is_state(
                        'binary_sensor.ablaknyito_szenzor_vendeghaz_ablakok',
                        'on'
                      )
                      and
                      states('climate.midea_ac_153931629743881')
                        != 'off'
                    }}
              sequence:
                - if:
                    - condition: template
                      value_template: |-
                        {{
                          states('climate.midea_ac_153931629743881')
                          != 'fan_only'
                        }}
                  then:
                    - action: climate.set_hvac_mode
                      target:
                        entity_id: climate.midea_ac_153931629743881
                      data:
                        hvac_mode: fan_only
                    - delay:
                        seconds: 1
                - action: climate.set_fan_mode
                  target:
                    entity_id: climate.midea_ac_153931629743881
                  data:
                    fan_mode: low
  - condition: state
    entity_id: binary_sensor.ablaknyito_szenzor_vendeghaz_ablakok
    state: 'off'
  - condition: template
    value_template: |-
      {{
        states('climate.midea_ac_153931629743881')
        == 'fan_only'
      }}
  - action: climate.set_hvac_mode
    target:
      entity_id: climate.midea_ac_153931629743881
    data:
      hvac_mode: '{{ eredeti_mod }}'
  - delay:
      seconds: 2
  - if:
      - condition: template
        value_template: |-
          {{
            eredeti_mod in ['cool', 'heat', 'auto']
            and eredeti_homerseklet is not none
          }}
    then:
      - action: climate.set_temperature
        target:
          entity_id: climate.midea_ac_153931629743881
        data:
          temperature: '{{ eredeti_homerseklet | float }}'
  - if:
      - condition: template
        value_template: |-
          {{
            eredeti_ventilator not in
            [none, '', 'unknown', 'unavailable']
          }}
    then:
      - action: climate.set_fan_mode
        target:
          entity_id: climate.midea_ac_153931629743881
        data:
          fan_mode: '{{ eredeti_ventilator }}'
  - if:
      - condition: template
        value_template: |-
          {{
            eredeti_preset not in
            [none, '', 'unknown', 'unavailable']
          }}
    then:
      - action: climate.set_preset_mode
        target:
          entity_id: climate.midea_ac_153931629743881
        data:
          preset_mode: '{{ eredeti_preset }}'
  - if:
      - condition: template
        value_template: |-
          {{
            eredeti_lenges not in
            [none, '', 'unknown', 'unavailable']
          }}
    then:
      - action: climate.set_swing_mode
        target:
          entity_id: climate.midea_ac_153931629743881
        data:
          swing_mode: '{{ eredeti_lenges }}'
mode: single
max_exceeded: silent

Összegzés

Fontos leszögezni, hogy ez az automatizálás nem ipari megoldás, és nem is annak készült. A működéséhez több rendszernek egyszerre kell rendelkezésre állnia: az ablaknyitás-érzékelőnek és a klímaberendezésnek kapcsolódnia kell a Wi-Fi-hálózathoz, működnie kell a Home Assistantot futtató szervernek, valamint elérhetőnek kell lennie a két épület közötti hálózati kapcsolatnak is.

A vendégház hálózati kiszolgálása egy vezeték nélküli pont–pont kapcsolaton keresztül történik. A Home Assistant szervere a másik épületben található, a két hálózat közötti kommunikációban pedig a korábbi cikkeimben részletesen bemutatott MikroTik router is részt vesz. Első ránézésre tehát meglehetősen sok összetevőből álló rendszer végzi el azt az egyszerűnek tűnő feladatot, hogy nyitott ablak esetén ventilátor üzemmódba kapcsolja a klímát.

A sok részegység ellenére a rendszer rendelkezésre állása a gyakorlatban meglepően magas. Ugyanakkor azt is érdemes figyelembe venni, hogy ezen az automatizáláson valójában semmilyen kritikus funkció nem múlik. Ha az érzékelő, a Wi-Fi-kapcsolat, a pont–pont összeköttetés, a router, a szerver vagy valamelyik szoftverkomponens éppen nem működik, a legrosszabb következmény az, hogy egy ideig nyitott ablak mellett üzemel a klíma – vagyis némi túlzással az udvart hűtöm vagy fűtöm.

Éppen ezért ebben az alkalmazásban elfogadhatónak tartom ezt a felépítést. Egy biztonsági, vagyonvédelmi vagy életvédelmi feladatot természetesen nem bíznék ennyi, egymástól függő komponensre megfelelő tartalék megoldások nélkül. Itt azonban egy kényelmi és energiatakarékossági funkcióról van szó, amely meghibásodás esetén sem állítja le a fűtést, nem teszi használhatatlanná a klímát, és nem okoz veszélyes állapotot.

A megoldás talán elsőre túl bonyolultnak tűnhet egy egyszerű ablakérzékelőhöz képest, de a szükséges infrastruktúra nagy része már korábban is rendelkezésre állt. Nekem csak az érzékelőt és a hozzá tartozó logikát kellett hozzáadnom. Cserébe nem kellett a klíma tápellátását kontaktorral megszakítanom, a működés szabadon módosítható, a firmware vezeték nélkül frissíthető, az automatizálás pedig később további feltételekkel és funkciókkal is bővíthető.