Integracja z rekuperatorem Defro DRX po MODBUS

Hej,

Nie widziałem nigdzie takiego tematu, więc postanowiłem założyć nowy i opisać jak zintegrować rekuperację na Defro. Wzorowałem się na wiedzy dostępnej w Internecie o rekuperatorze Thessli - podziękowania dla wszystkich użytkowników zaangażowanych w ten projekt bo było mi po prostu dużo łatwiej. Dodatkowo też skorzystałem z dokumentacji od samego producenta. Przejdźmy do konkretów.

Dashboard:

Co potrzebujemy?

  1. Konwerter MODBUS RS485 TCP przez Ethernet lub Wifi - ja skorzystałem z Elfin EW11A
  2. Zasilacz do konwertera: w moim przypadku 5-36V 5W - patrz komentarz poniżej

Problemy:

  1. Producent płytki Tech Sterowniki dla rekuperatora Defro przygotował jedynie komunikację (A/B) i nie ma wyprowadzonego zasilania, więc zgodnie z oficjalną informacją jaką uzyskałem należy zastosować osobny zasilacz…
  2. Brakuje obsługi jednego przypadku użycia - jeśli na ekranie sterownika zostanie zmieniony bieg (funkcja na 1-4 godziny), to takie ustawienie bierze priorytet i z ze strony MODBUS nie ma żadnego rejestru, który by, po pierwsze, pozwolił odczytać to ustawienie (brak informacji poza biegiem), oraz po drugie pozwolił nadpisać rejestr (zmiana biegu przez integrację nie będzie zaakceptowana). Zgłosiłem to do Defro. Drobna sprawa ale jednak dobrze by było mieć to obsłużone.

Pierwsze kroki:
Jak już mamy konwerter to trzeba go podpiąć do płytki rekuperatora. Można kupić gotowy przewód lub zarobić samemu. W moim przypadku wykorzystałem zwykłą skrętkę utp 5e. Następnie musimy się połączyć z konwerterem i skonfigurować ustawienia sieciowe. Szczegóły pomijam bo jest dużo informacji w internecie jak to poprawnie zrobić.

Konwerter konfigurujemy zgodnie z ustawieniami na sterowniku Defro (domyślne ustawienia):

Do tego potrzebujemy ustawienia serwera TCP:

Konfiguracja w Home Assistant:
Ustawiamy integrację MODBUS (można jedynie przez YAML):

# Modbus through TCP
# Elfin EW11A - Defro DRX V

  - name: DefroBMS
    host: 192.168.1.xxx
    port: 9999
    type: tcp
    delay: 5
    timeout: 15
    sensors:
      - name: "Defro - Wydatek Nawiewu"
        address: 100
        slave: 1
        device_class: volume_flow_rate
        unit_of_measurement: m³/h
        state_class: measurement
        scan_interval: 15
        unique_id: "defro_wydatek_nawiewu"
        
      - name: "Defro - Wydatek Wywiewu"
        slave: 1
        address: 101
        device_class: volume_flow_rate
        unit_of_measurement: m³/h
        state_class: measurement
        scan_interval: 15
        unique_id: "defro_wydatek_wywiewu"
        
      - name: "Defro - Bieg Nawiewu"
        address: 102
        slave: 1
        input_type: holding
        unique_id: "defro_bieg_nawiewu"
        
      - name: "Defro - Bieg Wywiewu"
        slave: 1
        address: 103
        input_type: holding
        unique_id: "defro_bieg_wywiewu"
        
      - name: "Defro - Bieg Zadany"
        address: 157
        slave: 1
        input_type: holding
        scan_interval: 15
        unique_id: "defro_bieg_zadany"

      - name: "Defro - Stan Filtrów"
        slave: 1
        address: 170
        unique_id: "defro_stan_filtrow"
        
      - name: "Defro - Temperatura Czerpnia"
        address: 104
        slave: 1
        unit_of_measurement: °C
        scale: 0.1
        precision: 1
        device_class: temperature
        state_class: measurement
        unique_id: "defro_temperatura_czerpnia"
        
      - name: "Defro - Temperatura Wyrzutnia"
        address: 105
        slave: 1
        unit_of_measurement: °C
        scale: 0.1
        precision: 1
        device_class: temperature
        state_class: measurement
        unique_id: "defro_temperatura_wyrzutnia"
        
      - name: "Defro - Temperatura Nawiew"
        address: 106
        slave: 1
        unit_of_measurement: °C
        scale: 0.1
        precision: 1
        device_class: temperature
        state_class: measurement
        unique_id: "defro_temperatura_nawiew"
        
      - name: "Defro - Temperatura Wywiew"
        address: 107
        slave: 1
        unit_of_measurement: °C
        scale: 0.1
        precision: 1
        device_class: temperature
        state_class: measurement
        unique_id: "defro_temperatura_wywiew"
        
      - name: "Defro - Temperatura Kontroli Nagrzewnicy"
        address: 109
        slave: 1
        unit_of_measurement: °C
        scale: 0.1
        precision: 1
        device_class: temperature
        state_class: measurement
        unique_id: "defro_temperatura_kontroli_nagrzewnicy"
        
      - name: "Defro - Przepływ Biegu 1"
        address: 164
        slave: 1
        input_type: holding
        unique_id: "defro_przeplyw_biegu_1"
        
      - name: "Defro - Przepływ Biegu 2"
        address: 165
        slave: 1
        input_type: holding
        unique_id: "defro_przeplyw_biegu_2"
        
      - name: "Defro - Przepływ Biegu 3"
        address: 166
        slave: 1
        input_type: holding
        unique_id: "defro_przeplyw_biegu_3"
        
      - name: "Defro - Błędy"
        address: 139
        slave: 1
        input_type: holding
        data_type: uint16
        unique_id: "defro_bledy"
        
      - name: "Defro - Bypass Dolna Temperatura"
        address: 173
        slave: 1
        input_type: holding
        unique_id: "defro_dolna_temperatura"
        
      - name: "Defro - Bypass Temperatura Komfortu"
        address: 174
        slave: 1
        input_type: holding
        unique_id: "defro_temperatura_komfortu"
        
    binary_sensors:
      - name: "Defro - Bypass Stan"
        address: 133
        slave: 1
        input_type: holding
        unique_id: "defro_bypass_stan"
        
      - name: "Defro - Urlop Stan"
        address: 137
        slave: 1
        input_type: holding
        unique_id: "defro_urlop_stan"
        
    switches:
      - name: "Defro - Bypass"
        address: 141
        slave: 1
        write_type: holding
        command_on: 1
        command_off: 0
        verify:
            address: 141
            input_type: holding
            state_on: 1
            state_off: 0
        unique_id: "defro_bypass"
        
      - name: "Defro - Tygodniówka"
        address: 156
        slave: 1
        write_type: holding
        command_on: 1
        command_off: 0
        verify:
            address: 156
            input_type: holding
            state_on: 1
            state_off: 0
        unique_id: "defro_tygodniowka"
        
      - name: "Defro - Flow Balancing"
        address: 168
        slave: 1
        write_type: holding
        command_on: 1
        command_off: 0
        verify:
            address: 168
            input_type: holding
            state_on: 1
            state_off: 0
        unique_id: "defro_flow_balancing"
        
      - name: "Defro - Urlop"
        address: 145
        slave: 1
        write_type: holding
        command_on: 60
        command_off: 0
        verify:
            address: 137
            input_type: holding
            state_on: 1
            state_off: 0
        unique_id: "defro_urlop"
        
      - name: "Defro - Okna"
        address: 158
        slave: 1
        write_type: holding
        command_on: 1
        command_off: 0
        verify:
            address: 158
            input_type: holding
            state_on: 1
            state_off: 0
        unique_id: "defro_okna"

Brakuje kilku funkcji, z których po prostu nie korzystam ale jak ktoś chce to może łatwo dodać: palenisko, tryb tygodniowy, GWC, jakieś dodatkowe ustawienia na przykład przy bypassie.

Dla głównego sensora od wentylatorów zrobiłem osobny YAML: /homeassistant/template/defro_fan_sensor.yaml

- fan:
    - name: "Defro - Fan Mode"
      unique_id: "fan.defro_fan_mode"
      state: >-
        {{ is_state('binary_sensor.defro_status', 'on') }}
      percentage: >-
        {% set gear = states('sensor.defro_bieg_zadany_max') | int(0) %}
        {% if gear == 1 %}
          {{ (states('sensor.defro_przeplyw_biegu_1') | float(0) / 450 * 100) | round(1) }}
        {% elif gear == 2 %}
          {{ (states('sensor.defro_przeplyw_biegu_2') | float(0) / 450 * 100) | round(1) }}
        {% elif gear == 3 %}
          {{ (states('sensor.defro_przeplyw_biegu_3') | float(0) / 450 * 100) | round(1) }}
        {% else %}
          0
        {% endif %}
      speed_count: 3

      turn_on:
        - action: modbus.write_register
          data:
            slave: 1
            address: 157
            value: >-
              {% set p = percentage | int %}
              {% if p <= 0 %} 0
              {% elif p <= 33 %} 1
              {% elif p <= 66 %} 2
              {% else %} 3
              {% endif %}
            hub: DefroBMS

      turn_off:
        - action: modbus.write_register
          data:
            slave: 1
            address: 157
            value: 0
            hub: DefroBMS

      set_percentage:
        - action: modbus.write_register
          data:
            slave: 1
            address: 157
            value: >-
              {% set p = percentage | int %}
              {% if p <= 0 %} 0
              {% elif p <= 33 %} 1
              {% elif p <= 66 %} 2
              {% else %} 3
              {% endif %}
            hub: DefroBMS

      preset_modes:
        - "normalny"
        - "urlop"
        - "okna"

      preset_mode: >-
        {% if is_state('switch.defro_urlop', 'on') %}
          urlop
        {% elif is_state('switch.defro_okna', 'on') %}
          okna
        {% else %}
          normalny
        {% endif %}

      set_preset_mode:
        - choose:
            - conditions: "{{ preset_mode == 'urlop' }}"
              sequence:
                - action: switch.turn_off
                  target:
                    entity_id:
                      - switch.defro_okna
                - action: switch.turn_on
                  target:
                    entity_id: switch.defro_urlop

            - conditions: "{{ preset_mode == 'okna' }}"
              sequence:
                - action: switch.turn_off
                  target:
                    entity_id:
                      - switch.defro_urlop
                - action: switch.turn_on
                  target:
                    entity_id: switch.defro_okna

            - conditions: "{{ preset_mode == 'normalny' }}"
              sequence:
                - action: switch.turn_off
                  target:
                    entity_id:
                      - switch.defro_urlop
                      - switch.defro_okna

Pozostałe sensory są w kolejnym YAML: /homeassistant/template/defro_template_sensors.yaml

- sensor:
    - name: "Defro - Sprawność"
      unique_id: "sensor.defro_sprawnosc"
      unit_of_measurement: "%"
      state_class: "measurement"
      state: >-
        {% if is_state('binary_sensor.defro_bypass_stan', 'off') %}
          {% set t1 = states('sensor.defro_temperatura_czerpnia') | float(0) %}
          {% set t2 = states('sensor.defro_temperatura_nawiew') | float(0) %}
          {% set t3 = states('sensor.defro_temperatura_wywiew') | float(0) %}
          {% if (t3 - t1) != 0 %}
            {{ ((t2 - t1) / (t3 - t1) * 100) | round(1, default=0) }}
          {% else %}
            0
          {% endif %}
        {% else %}
          0
        {% endif %}

    - name: "Defro - Odzyskana Moc"
      unique_id: "sensor.defro_odzyskana_moc"
      unit_of_measurement: "W"
      state_class: "measurement"
      state: >-
        {% if is_state('binary_sensor.defro_bypass_stan', 'off') %}
          {% set strumienN = states('sensor.defro_wydatek_nawiewu') | float(0) %}
          {% set tcz = states('sensor.defro_temperatura_czerpnia') | float(0) %}
          {% set tn = states('sensor.defro_temperatura_nawiew') | float(0) %}
          {% set odzysk = ((tn - tcz) * strumienN * 1200) / 3600 %}
          {% if tcz < strumienN %}
            {{ odzysk | float | round(1, default=0) }}
          {% else %}
            {{ (odzysk * -1) | float | round(1, default=0) }}
          {% endif %}
        {% else %}
          0
        {% endif %}

    - name: "Defro - Wysterowanie Wywiew"
      unique_id: "sensor.defro_wysterowanie_wywiew"
      unit_of_measurement: "%"
      state_class: "measurement"
      state: >-
        {% set flowW = states('sensor.defro_wydatek_wywiewu') | float(0) %}
        {{ ((flowW * 100) / 450) | float | round(1, default=0) }}

    - name: "Defro - Wysterowanie Nawiew"
      unique_id: "sensor.defro_wysterowanie_nawiew"
      unit_of_measurement: "%"
      state_class: "measurement"
      state: >-
        {% set flowN = states('sensor.defro_wydatek_nawiewu') | float(0) %}
        {{ ((flowN * 100) / 450) | float | round(1, default=0) }}

    - name: "Defro - Błedy Stan"
      unique_id: "sensor.defro_bledy_stan"
      state: >-
        {% set val = states('sensor.defro_bledy') | int(0) %}
        {% set binary = '{0:b}'.format(val) %}
        {% set data = namespace(positions=[]) %}

        {% for i in range(binary | length) %}
          {% if binary[-1 - i] == '1' %}
            {% set data.positions = data.positions + [i + 1] %}
          {% endif %}
        {% endfor %}

        {% set errors = {
          1: "Błąd wentylatora wywiewu",
          2: "Błąd wentylatora nawiewu",
          3: "Błąd czujnika temperatury zewnętrznej",
          4: "Błąd czujnika temperatury wywiewu",
          5: "Błąd czujnika temperatury nawiewu",
          6: "Błąd czujnika temperatury wyrzut",
          7: "Błąd czujnika temperatury nawilżacza",
          10: "Błąd czujnika przepływu wywiewu",
          11: "Błąd czujnika przepływu nawiewu",
          12: "Błąd czujnika nawilżacza",
          13: "Błąd czujnika nagrzewnicy GWC",
          14: "Błąd czujnika temperatury nagrzewnicy nawilżacza",
          15: "Błąd wentylatora wywiewu przepływ",
          16: "Błąd wentylatora nawiewu przepływ"
        } %}

        {% set ns = namespace(active_errors=[]) %}
        {% for pos in data.positions %}
          {% if errors[pos] is defined %}
            {% set ns.active_errors = ns.active_errors + [errors[pos]] %}
          {% endif %}
        {% endfor %}

        {{ ns.active_errors if ns.active_errors else "OK" }}

    - name: "Defro - Bieg Zadany Max"
      unique_id: "defro_bieg_zadany_max"
      state: >-
        {{ [
          states('sensor.defro_bieg_nawiewu') | int(0),
          states('sensor.defro_bieg_wywiewu') | int(0)
        ] | max }}

- binary_sensor:
    - name: "Defro - Status"
      unique_id: "binary_sensor.defro_status"
      state: >-
        {% set val = states('sensor.defro_bieg_zadany') | int(0) %}
        {{ 'off' if val == 0 else 'on' }}

    - name: "Defro - Okna Stan"
      unique_id: "binary_sensor.defro_okna_stan"
      state: >-
        {{ is_state('switch.defro_okna', 'on') }}

    - name: "Defro - Awaria"
      unique_id: "binary_sensor.defro_awaria"
      state: >-
        {{ states('sensor.defro_bledy') | int(0) != 0 }}

Oczywiście do głównego pliku konfiguracyjnego /homeassistant/configuration.yaml musimy dodać odpowiednio:

template: !include_dir_merge_list template/
modbus: !include modbus.yaml

Kod dla vertical stack card:

type: vertical-stack
cards:
  - type: picture-elements
    elements:
      - type: state-label
        entity: sensor.defro_temperatura_czerpnia
        style:
          top: 33%
          left: 7%
          color: black
          font-family: system-ui
      - type: state-label
        entity: sensor.defro_temperatura_wywiew
        style:
          top: 33%
          left: 93%
          color: black
          font-family: system-ui
      - type: state-label
        entity: sensor.defro_temperatura_wyrzutnia
        style:
          top: 66.8%
          left: 7%
          color: black
          font-family: system-ui
      - type: state-label
        entity: sensor.defro_temperatura_nawiew
        style:
          top: 66.8%
          left: 93%
          color: black
          font-family: system-ui
      - type: state-label
        entity: sensor.defro_temperatura_kontroli_nagrzewnicy
        style:
          top: 21%
          left: 37%
          color: black
          font-family: system-ui
          font-size: smaller
      - type: state-label
        entity: sensor.defro_wydatek_nawiewu
        style:
          top: 82%
          left: 92%
      - type: state-label
        entity: sensor.defro_wysterowanie_nawiew
        style:
          top: 82%
          left: 66%
          color: black
          font-family: system-ui
          font-size: smaller
      - type: state-label
        entity: sensor.defro_wydatek_wywiewu
        style:
          top: 18%
          left: 92%
      - type: state-label
        entity: sensor.defro_wysterowanie_wywiew
        style:
          top: 82%
          left: 35%
          color: black
          font-family: system-ui
          font-size: smaller
      - type: state-label
        entity: sensor.defro_sprawnosc
        style:
          top: 72%
          left: 50%
          color: black
          font-family: system-ui
          font-size: smaller
      - type: state-label
        entity: sensor.defro_odzyskana_moc
        style:
          top: 29%
          left: 50%
          color: black
          font-family: system-ui
          font-size: smaller
      - type: state-label
        entity: sensor.defro_bieg_nawiewu
        style:
          top: 52%
          left: 65.5%
          color: black
          font-weight: bold
      - type: state-label
        entity: sensor.defro_bieg_wywiewu
        style:
          top: 52%
          left: 34.5%
          color: black
          font-weight: bold
      - type: state-label
        entity: sensor.shellyemminig4_7c2c6777361c_moc
        style:
          top: 19%
          left: 50%
          color: black
          font-family: system-ui
          font-size: smaller
    image: /local/defro/defro1v.png


Chciałbym jeszcze w przyszłości usprawnić działanie karty i pokazać bypass oraz może kilka innych ustawień na wzór integracji z Thessli ale to może kiedyś. :slightly_smiling_face:

Pozdrawiam,
Piotr

4 Likes

naprawdę super.
czy do pełnego rozwiązania możesz podsunać yaml z karty fan ?

jest powyżej w defro_fan_sensor.yaml, czy o coś innego chodzi?

bardziej mi chodziło o kod dla poniższej karty fan:

To jest właśnie ten sensor - karta to zwykły tile card.

type: tile
grid_options:
  columns: full
  rows: 2
entity: fan.defro_fan_mode
name: Fan Mode
state_content:
  - state
  - preset_mode
vertical: false
features:
  - type: fan-speed
  - type: fan-preset-modes
    style: dropdown
features_position: bottom
1 Like

Trochę poprawiłem grafikę karty (oś symetrii) i dodałem cienie:

1 Like

Cześć. Od dłuższego czasu próbuję sterować swoją centralą DRX400 (także i tym opisanym tutaj sposobem) - i “wszystko działa” - oprócz kilku rejestrów - m.in. 157 (którym spodziewałem się zmieniać biegi wentylatorów). Czy jest możliwe że sterownik odrzuca zmiany rejestrów ze względu na jakieś zależności swojej logiki (i należy wprowadzić centralę w jakiś konkretny stan)?

Cześć. Jaki masz problemy z tym rejestrem 157? Może będę mógł pomóc. Można też napisać do Defro, aczkolwiek moje doświadczenia są takie sobie (pisałem w pierwszym poście). Musisz mieć rekuperator w trybie “normalnego” działania - jak będzie na przykład urlop (numer “4”) albo chociaż ochrona przed zamarzaniem (przełącza się między zadanym trybem, a numerem “5”) to nie zmienisz po modbus. Czyli jak masz tryb pierwszy, a wskoczy Ci piątka bo akurat działa grzałka albo włączysz tryb urlop czy inny to musisz wrócić albo poczekać aż się wróci do jedynki.

Cześć, miałem ten sam problem. Okazało się, że sterownik posiadał starszą wersję oprogramowania (Wersja modułu MBP 1.1.4), w którym mocno jest ograniczona liczba rejestrów. W tej wersji obsługa kończy się na rejestrze 155, a próby odczytu wyższych adresów zwracają błąd komunikacji. W serwisie Defro dowiedziałem się, że w starszych wersjach oprogramowania funkcje takie jak zaawansowane sterowanie GWC, nagrzewnicami wtórnymi czy szczegółowe statystyki czujników CO2/wilgotności nie były jeszcze zainstalowane w protokole Modbus lub znajdowały się w innych obszarach pamięci, których ta wersja modułu nie udostępnia.
Dostęp do nowszych funkcji (powyżej rejestru 155) daje dopiero zaktualizowane oprogramowanie. Najnowsza wersja dla sterownika Medium, który jest przeznaczonych do central typu 300/400/500 to wersja 1.2.10. Pozdrawiam.

1 Like

Ja mam ST-340 V2 Medium i aktualnie wersję firmware 2.1.20 GMBP, a od producenta sterownika (Tech) otrzymałem wersję “2.1.61G” - przy czym po upgrade wyszło na to że zaktualizował się tylko wyświetlacz a moduł centrali jest nadal w starej wersji i dostaje komunikat “Nieprawidłowa wersja oprogramowania”.

Swoją drogą doceniam dobry kontakt z Defro - ja dostałem tylko zdawkową odpowiedź że wiedzą jaka jest najnowsza wersja - ale jej nie mają..

Proszę spróbować wpiąć pendrive z nowym oprogramowaniem otrzymanym od Tech Sterowniki do ekranu i powtórzyć aktualizację, ale najpierw odłączyć rekuperator całkowicie od zasilania. Powinien wystartować i zaktualizować zarówno ekran jak i moduł. Gdyby się nie udało to druga możliwość jest taka, że można wpiąć pendrive’a bezpośrednio w moduł (po zdjęciu obudowy, na płytce jest gniazdo usb).

Słuszna uwaga - rekuperacja znów działa i to razem z upragnionym sterowaniem po Modbus :slight_smile: Bardzo dziękuję za pomoc!

A swoją drogą - czy być może jest gdzieś dostępna “instrukcja typowo serwisowa”? Bo skoro w “Instrukcji obsługi” są opisane rejestry (to na plus), ale wg niej Aktualizacja oprogramowania miałaby polegać na włożeniu pendrive i “w tym momencie aktualizuje się moduł wraz z panelem”.