Asystent AI
Powiadomienia
Wyczyść wszystko

Supla [Rozwiązany] Pozycja Rolety MQTT

3 Wpisów
2 Użytkownicy
0 Reactions
3,955 Wyświetleń
(@martinsnow)
Wpisów: 3
Bywalec
Autor tematu
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 
[#1524]

Hejka, walczę już z tym ze dwa tygodnie, mianowicie mam problem ze sterowaniem rolet, a dokładnie z tym aby zmusić suwak do działania ;) , aktualnie przesyła do brokera tylko samą pozycje ('gołą' liczbę np: 50), podpowie ktoś jak to powinno wyglądać, żeby szła komenda w postaci {id:3646, shut: tutaj wartość po przesunięciu suwaka}.
W cover.yaml mam takie coś i w sumie działa tylko ten brak sterowania dokładną pozycją:

- platform: mqtt
  name: "Salon"
  state_topic: "supla/channels/status/rollershutter/3646"  
  command_topic: "supla/channels/command/rollershutter/3646"
  position_topic: "supla/channels/status/rollershutter/3646"
  set_position_topic: "supla/channels/command/rollershutter/3646"
#  set_position_template: "??????????"
  retain: true
  position_open: 0
  position_closed: 100
  payload_open: '{ "id": 3646, "shut": 0 }'
  payload_close: '{ "id": 3646, "shut": 100 }'
  state_open: '{"id": 3646, "shut": 0, "sensor_1": 0, "online": 1}'
  state_closed: '{"id": 3646, "shut": 100, "sensor_1": 0, "online": 1}' 
  value_template: "{{ value_json.shut }}"
  device_class: shutter 

roleta zgłasza sie tak:

{"id": 3646, "shut": 0, "sensor_1": 0, "online": 1}

 
Dodane : 12/02/2020 11:08 pm
(@martinsnow)
Wpisów: 3
Bywalec
Autor tematu
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Sam sobie odpowiem

 set_position_template: '{"id": 3646, "shut": {{ 100-position }} }'

 
Dodane : 14/02/2020 12:55 pm
(@dariuszniepieklo)
Wpisów: 7
Członek WeCU
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Cześć @martinsnow — temat masz rozwiązany dobrze i Twoja samodzielna odpowiedź jest poprawna (set_position_template z 100-position to klasyczny przypadek inwersji konwencji między Supla i HA). Wracam do wątku po 6 latach, bo Google podsyła tu masę ludzi szukających "pozycja rolet MQTT" i warto zostawić rozbudowany kontekst dla tych, którzy trafią z innym stackiem niż Supla. Daję podsumowanie z perspektywy 13 stref rolet produkcyjnie spiętych z HA przez Modbus i MQTT.

Dlaczego Twoja inwersja 100-position zadziałała

Krótko, dla zaglądających:

  • Konwencja HA: position=0 = zamknięte, position=100 = w pełni otwarte
  • Konwencja Supla MQTT: shut=0 = w pełni otwarte (0% zasłonięcia), shut=100 = w pełni zamknięte (100% zasłonięcia)

Czyli shut = 100 - position. To samo dotyczy płaszczyzny "stan" (state_topic) — przy odczycie pozycji z Supli też masz 100 - shut, ale w value_template HA większość ludzi pomija ten krok, bo device_class: shutter i tak rysuje suwak w odwrotnej skali (większa pozycja = wyżej otwarte). Praktyka pokazuje, że i tak warto być spójnym i odwracać w obu kierunkach, żeby nie pomieszać sobie statystyk i automatyk wykorzystujących pozycje liczbowe.

Pułapka kalibracji konwencji — różne urządzenia mają różne stany "0":

Stack 0 oznacza 100 oznacza
HA cover zamknięte otwarte
Supla MQTT (shut) otwarte zamknięte
Fibaro Roller Shutter Z-Wave otwarte zamknięte
Shelly 2.5/Plus 2PM zamknięte otwarte
KNX otwarte zamknięte
Modbus (custom PLC) dowolne — definiujesz sam  

Czyli pierwsza rzecz przy każdym nowym roletowym device w HA: sprawdź konwencję 0/100 i odwracaj jeśli trzeba. To rozwiązanie martinsnow działa dla Supli; dla Shelly nie odwracasz; dla Z-Wave Fibaro znowu odwracasz.

Skąd urządzenie wie, ile to jest "50%"

Tu jest sedno, bo to nieoczywiste i jest najczęstszym źródłem frustracji.

Rolety standardowo nie mają enkodera pozycji. Mają tylko dwa krańcówki (full-open, full-close). Wszystko między nimi to liczenie czasu:

  1. Kalibracja: jedziesz raz do góry (zaczyna czas T_up), jedziesz raz do dołu (T_down) — to są stałe czasowe danej rolety (zwykle 18-30 sekund)
  2. Pozycja liczona = (czas_jazdy_dotąd / T_full) × 100
  3. Gdy każesz "pozycja 50%", urządzenie:
    • Sprawdza obecną pozycję
    • Liczy różnicę → kierunek + ile sekund
    • Wystawia komendę "góra/dół przez X sekund"
    • Po X sekundach zatrzymuje

Konsekwencja: kalibracja odjeżdża z czasem. Każdy klik "stop" w połowie ruchu wprowadza mikro-dryf. Po 30-60 cyklach masz błąd 5-10%. Trzeba albo:

  • Co X cykli wymuszać pełen end-of-travel (do końca jednego z kierunków) → wtedy resetujesz pozycję na 0 lub 100 z czujnika krańcowego
  • Albo mieć flag "needs recalibration" który po przekroczeniu progu mówi userowi "podjedź do końca"

U mnie w 13 strefach robi to PLC autonomicznie — co kilkanaście jazd flag M_NEED_CALIB zapala się i przy następnym pełnym ruchu góra/dół następuje twardy reset pozycji.

Stack 1 (najprostszy): Supla / Shelly / Tasmota + HA + MQTT

To co masz martinsnow. Konfig jak Twój, plus:

 
 
yaml
cover:
  - platform: mqtt
    name: "Salon"
    command_topic: "supla/channels/command/rollershutter/3646"
    state_topic: "supla/channels/status/rollershutter/3646"
    position_topic: "supla/channels/status/rollershutter/3646"
    set_position_topic: "supla/channels/command/rollershutter/3646"
    set_position_template: '{"id": 3646, "shut": {{ 100 - position }} }'
    value_template: "{{ 100 - value_json.shut }}"
    position_open: 100
    position_closed: 0
    payload_open: '{ "id": 3646, "shut": 0 }'
    payload_close: '{ "id": 3646, "shut": 100 }'
    payload_stop: '{ "id": 3646, "shut": "STOP" }'
    device_class: shutter
    retain: true
    optimistic: false
    availability_topic: "supla/channels/status/rollershutter/3646/online"
    payload_available: '1'
    payload_not_available: '0'
    qos: 1

Co dodałem względem Twojego oryginału (znowu — dla każdego nowego czytającego):

  • value_template z inwersją — żeby suwak HA odzwierciedlał faktyczną pozycję zamiast wartości "shut"
  • position_open: 100, position_closed: 0 — explicit
  • payload_stop — żeby przycisk STOP w HA działał
  • availability_topic — HA wie kiedy device online vs offline (kluczowe dla automatyk: nie chcesz triggerować rolety która nie odpowiada)
  • optimistic: false — HA czeka na potwierdzenie pozycji, nie zakłada że komenda się udała
  • qos: 1 — at-least-once (przy qos: 0 możesz stracić komendę jeśli broker będzie restartował się akurat w tym czasie)

Stack 2 (PLC-based): Fatek / Wago / Siemens + HA przez Modbus TCP

Architektura dla setupów wielostrefowych (5+ rolet). Brak MQTT, brak ESP w roletach — tylko PLC sterujący kasetkami przekaźnikowymi i HA czytający/piszący do PLC przez Modbus TCP.

Schemat rejestrów Modbus (dla N rolet, zakres R5000..R5000+N):

Rejestr Funkcja Zakres
R5000+N aktualna pozycja rolety N (R_POS_CUR) 0-100
R5100+N docelowa pozycja rolety N (R_POS_TGT) 0-100
R5200+N stan rolety N (R_STATE: 0=idle, 1=up, 2=down, 3=calib) 0-3
M_NEED_CALIB flaga "wymaga rekalibracji" rolety N bit

W HA:

 
 
yaml
modbus:
  - name: fatek_plc
    type: tcp
    host: 192.168.1.50
    port: 502

cover:
  - platform: template
    covers:
      roleta_salon:
        friendly_name: "Roleta Salon"
        position_template: "{{ states('sensor.roleta_salon_pozycja_cur') | int }}"
        open_cover:
          service: modbus.write_register
          data:
            hub: fatek_plc
            address: 5100   # R_POS_TGT salon
            value: 100
        close_cover:
          service: modbus.write_register
          data:
            hub: fatek_plc
            address: 5100
            value: 0
        set_cover_position:
          service: modbus.write_register
          data:
            hub: fatek_plc
            address: 5100
            value: "{{ position }}"
        stop_cover:
          service: modbus.write_coil
          data:
            hub: fatek_plc
            address: 800   # M800 = stop
            state: true

sensor:
  - platform: modbus
    name: roleta_salon_pozycja_cur
    hub: fatek_plc
    address: 5000   # R_POS_CUR
    unit_of_measurement: "%"
    scan_interval: 1

Zalety vs stack MQTT:

  • Deterministyczne czasy — Modbus TCP ma <50 ms round-trip, MQTT przez broker może być 200-500 ms (a przy odpalonym Frigate/Plex/inne → niestabilne)
  • Brak brokera w środku — mniej części, mniej awarii
  • PLC liczy pozycję sam, dokładność wyższa niż ESP (PLC nie ma garbage collectora, nie restartuje się przy aktualizacji)
  • Pozycja robi się w PLC, nie w HA — fizyczny włącznik na ścianie też ją aktualizuje
  • Działa bez HA — fizyczne przyciski w pomieszczeniu reagują natychmiast, HA tylko orkiestruje

Wady:

  • Wymaga PLC (3-5k zł na start) — nieopłacalne dla 2-3 rolet
  • Trzeba umieć pisać ladder logic w WinProladder/CODESYS
  • Modbus binding w HA jest bardziej "techniczny" niż auto-discovery MQTT

Pułapki które złapałem przy 13 strefach

Z 5 lat utrzymania produkcyjnego stack'a:

  1. HA Modbus "stuck flag" bug — przy restarcie HA czasem zostawia flagi M ustawione w PLC z poprzedniej sesji. Workaround: watchdog w ladderze, który co X sekund jeśli HA_alive_flag == 0 (HA nie pisze) → RST wszystkich command-flags. U mnie to są flagi M1950-M1967
  2. Drift pozycji przy częstym stopowaniu — jeśli ktoś klika "stop, stop, stop" w połowie ruchu, pozycja drifftuje. Rozwiązanie: counter "ile razy zatrzymano w środku" → po przekroczeniu progu (np. 10) zapal M_NEED_CALIB. W praktyce u mnie ten mechanizm jest drugą linią obrony — pierwszą jest auto-kalibracja co noc (patrz sekcja niżej), więc M_NEED_CALIB rzadko ma okazję się zaświecić."Przy następnym pełnym ruchu góra/dół twardo zresetuj R_POS_CUR = 0 (na czujniku end-bottom) albo R_POS_CUR = 100 (na end-top). 
  3. Tilt dla żaluzji aluminiowych (martinsnow ma rolety zewnętrzne, więc go to nie dotyczy, ale wielu czytelników może mieć) — żaluzje z lamelami potrzebują drugiej wartości "tilt 0-100" obok pozycji. HA wspiera to przez tilt_command_topic i tilt_position_topic. W PLC robisz to osobnym rejestrem R_TILT, sterowanie wymaga krótkich impulsów (~100-500 ms zamiast pełnej jazdy)
  4. Rolety z silnikiem AC bez sygnału feedback — silnik kręci, ale jak roleta zablokowała się (śnieg, gałąź, dzieci podłożyły coś pod)? PLC nie wie. Workaround: prądomierz/pomiar PV silnika → jeśli prąd > 50% nominalnego po końcu spodziewanego czasu → STOP + alarm. To "miękki" sensor zablokowania
  5. Konflikt komend — HA wysyła "pozycja 50%", w tym czasie ktoś klika fizyczny przycisk "góra". Kto wygrywa? U mnie w ladderze: fizyczny przycisk zawsze wygrywa (override). HA to "miła propozycja", którą ladder akceptuje tylko jeśli żaden fizyczny przycisk nie jest aktywny w danej chwili
  6. MQTT retain dla pozycjiretain: true jest niezbędne dla state_topic, żeby HA po restarcie znało ostatnią znaną pozycję. Bez retain HA pokazuje "unknown" do pierwszej zmiany pozycji
  7. Zaokrąglanie pozycji — Supla wysyła shut jako integer 0-100. Jeśli zrobisz value_template: "{{ 100 - value_json.shut }}" i wartość wynosi 0 zamiast brak klucza → HA traktuje to jako "zamknięte". Zabezpieczenie: default(0) w template

Best practice: auto-kalibracja co noc — dlaczego drift przestaje istnieć

To jest pattern, który u mnie rozwiązał problem driftu raz na zawsze i którego nie widziałem nigdzie opisanego po polsku, więc zostawiam tu w wątku. Idea jest prosta — zamiast walczyć z driftem (counter, flag "needs recalibration", user-prompt "podjedź do końca"), PLC kalibruje wszystkie rolety automatycznie w nocy, bez wiedzy mieszkańców.

Mechanizm:

O godzinie X (u mnie 03:15, bo wtedy z wysokim prawdopodobieństwem nikt nie operuje roletami) PLC dla każdej rolety wykonuje sekwencję:

  1. Sprawdza czy w ciągu ostatnich N godzin (u mnie 4h) nikt nie operował tą roletą ręcznie. Jeśli była zmiana — skip (ktoś nie śpi, nie chcemy go budzić nocnym ruchem)
  2. Sprawdza czy roleta nie jest w IGNORE_LIST (osobny rejestr w PLC ustawialny z HA — np. "okno sypialni Ani, nie ruszać")
  3. Wystawia komendę "jedź w dół" przez T_full_down + 5 sekund (5s overshoot)
  4. Po zakończeniu cyklu twardo ustawia R_POS_CUR = 0 (rolety i tak fizycznie blokują się na krańcowniku dolnym, więc 5 sekund nadmiaru nie szkodzi — silnik tylko gęściej hummi przed zatrzymaniem przez bezpiecznik termiczny w głowicy)
  5. Loguje timestamp do R_LAST_CALIB_N
  6. Przerwa 10 sekund między roletami (żeby nie ciągnąć prądu wszystkimi silnikami naraz — 13 rolet × ~300 W jednocześnie = ~4 kW startu)

Rezultat: każdego ranka start dnia od zera kalibracji. Drift kumulowany z dnia poprzedniego = zresetowany. Nieważne ile razy ktoś klikał "stop, stop, stop" w połowie ruchu, ile razy HA wysłał komendę i się rozjechał, ile razy mikrokontroler w głowicy żółwią — o 7:00 każda roleta zaczyna dzień od pewnej, hardcoded pozycji 0.

Konsekwencje dodatkowe:

  • Czasowy model pozycji w ciągu dnia staje się dokładny (błąd <5% przez cały dzień, bo kumuluje się tylko 16-18h zamiast tygodni)
  • M_NEED_CALIB flag nie jest już potrzebny do interakcji z userem (PLC sam o tym zadba) — zostaje tylko jako sygnał diagnostyczny dla loga
  • Cykl życia silnika — paradoksalnie wydłuża się, bo zamiast wielu drobnych "stop w połowie ruchu" (każdy taki stop to inercja + mikro-zatarcie) silnik dostaje jeden pełen zamknięty cykl na koniec dnia, co czyści mechanikę
  • Diagnostyka awarii — jeśli któraś roleta nie zakończyła kalibracji w spodziewanym czasie (np. czas jazdy 30s zamiast 22s) → flag w PLC + powiadomienie do HA → user dostaje rano "Roleta w pokoju Ani jechała 30% dłużej niż zwykle — sprawdź, czy nie ma blokady"

Fragment ladder Fatek (uproszczony, dla 1 rolety):

 
 
; Trigger nocny: RTC godzina 03:15
|--[ R4131 == K3 ]--[ R4130 == K15 ]--[ M1924↑ co minutę ]--+
|                                                            |
|                                                            +--[ /M_USER_RECENT ]--[ /M_IGNORE ]--( SET M_AUTOCALIB )

; Auto-kalib body — jedź w dół przez T_full + 5s
|--[ M_AUTOCALIB ]--+--( Y_dol )                  ; włącz silnik dół
|                   +--( TMR T200 K=270 )         ; T200 base 0.1s, 270 = 27 sekund (T_full=22s + 5s)

; Po T200 — zatrzymaj i twardo zresetuj pozycję
|--[ T200 ]--+--( RST Y_dol )                     ; stop silnik
|            +--( MOV K0 R_POS_CUR )              ; HARDCODED pozycja 0
|            +--( MOV R_LAST_CALIB_TS R5500 )     ; log timestamp ostatniej kalibracji
|            +--( RST M_AUTOCALIB )
|            +--( SET M_NEXT_CALIB_DELAY )        ; trigger 10s przerwy przed następną roletą

Co kontroluje user z HA:

  • Switch auto_calibration_enabled (master on/off, np. wyjeżdżając na wakacje wyłączasz)
  • Switch per-roleta roleta_X_autocalib_ignore (np. okno przy łóżku Ani — nie ruszać o 3:15)
  • Sensor roleta_X_last_calibrated — pokazuje "kiedy ostatnio skalibrowane" (debug)
  • Time picker autocalib_hour — domyślnie 3:15, ale rodzina nocnego trybu pracy może ustawić na 14:00 (jak wszyscy w pracy)

Pułapka, na którą trzeba uważać:

Sprawdzaj czy roleta nie jest zablokowana (np. niedomknięte okno otwarte do środka i roleta o nie hakuje). Jeśli silnik ciągnie prąd przez czas dłuższy niż T_full + tolerancja, a Y_dol jest aktywne — STOP, alarm, nie wykonuj kolejnych kalibracji aż user potwierdzi w HA. Inaczej zniszczysz mechanizm rolety przez nocne wymuszanie ruchu na zablokowanym torze.

Integracja z pogodynką — daylight harvesting dla żaluzji fasadowych

Dochodzimy do najfajniejszej części, czyli powodu, dla którego w ogóle warto ciągnąć skrętkę na dach pod własną pogodynkę i mieć kontrolę pozycji+tilt w PLC. To pattern znany w komercyjnych budynkach jako daylight harvesting (LEED EQ Credit 8.1), zaadaptowany do domu — i działa najlepiej z żaluzjami fasadowymi (Aluprof, Selt, Helar, Warema), które mają niezależne sterowanie wysokością (0-100%) i kątem lameli (0-90°). Zwykłe rolety zewnętrzne tego nie zrobią — to jest argument za żaluzjami fasadowymi w pomieszczeniach gdzie spędzasz najwięcej czasu z ekranem przed sobą (biuro, salon z TV, kuchnia z laptopem).

Problem, który rozwiązuje:

Latem o 14:00 w słoneczny dzień natężenie na zewnątrz to 80-100 klx. Komfortowe natężenie do pracy z ekranem to 300-500 lx (norma EN 12464-1 dla biura). To różnica 200×. Trzy typowe scenariusze, wszystkie złe:

  1. Żaluzje otwarte całkiem → oślepia, refleksy na monitorze, oczy bolą po godzinie
  2. Żaluzje zamknięte całkiem → ciemno, włączasz światło sztuczne, klimatyzacja musi pracować bo i tak duża masa termiczna fasady
  3. Ustawiasz ręcznie raz na 2 godziny → wzwy, męczące, nigdy nie idealne

Rozwiązanie: PLC + pogodynka liczy w czasie rzeczywistym, jaki powinien być tilt lameli (a opcjonalnie też height) aby do pomieszczenia trafiało stałe natężenie ~400 lx, niezależnie od pogody na zewnątrz.

Wejścia algorytmu:

Sygnał Źródło Częstotliwość Po co
Lux outdoor Pogodynka (BH1750 lub Lumel) 5-60 s natężenie do skalowania
Azimuth + elevation słońca HA sun.sun component (oblicza z RTC + GPS) 60 s wiesz gdzie jest słońce
Temp zewnętrzna Pogodynka (DS18B20 / BMP280) 60 s bonus: lato/zima inny target
Stan zachmurzenia OpenWeatherMap lub lux trend 5 min gładkie przejścia
Konfiguracja okna Per-roleta w PLC: azimuth fasady (np. południe=180°) static kiedy słońce świeci w to konkretne okno
"Screen flag" pomieszczenia Per-roleta: M-bit "tu jest ekran" static agresywniejszy algorytm
User override timer Per-roleta: timer ostatniej manualnej operacji per-event szanuj decyzję usera przez 2h

Algorytm (uproszczony, działa w lader Fatek):

 
 
; Krok 1 — czy słońce świeci w to okno?
; window_azimuth_min = 180-90 = 90° (wschód-południe-zachód)
; window_azimuth_max = 180+90 = 270°
; sun_in_window = (sun_azimuth ≥ 90 AND sun_azimuth ≤ 270 AND sun_elevation > 10°)

; Krok 2 — bazowy tilt z lux
IF lux_outdoor < 2000:        tilt_base = 0    ; pochmurno, otwórz max
ELSE IF lux_outdoor < 15000:  tilt_base = 30   ; jasno
ELSE IF lux_outdoor < 50000:  tilt_base = 50   ; bardzo jasno
ELSE:                          tilt_base = 70   ; oślepiające

; Krok 3 — korekta kąta padania
; Gdy słońce świeci pod ostrym kątem (zachód), potrzebny większy tilt
sun_correction = (90 - sun_elevation) / 3

; Krok 4 — screen flag (biuro, salon z TV)
screen_offset = (M_HAS_SCREEN AND sun_in_window) ? 15 : 0

; Krok 5 — final tilt z saturation
tilt_final = MIN(90, tilt_base + sun_correction + screen_offset)

; Krok 6 — hysteresis (nie zmieniaj jeśli różnica <5°)
IF |tilt_final - tilt_current| < 5: skip
ELSE: MOV tilt_final R_TILT_TGT[N]

Co to daje w praktyce u mnie:

  • W biurze monitor zachowuje stałe natężenie ~400 lx przez cały dzień bez ręcznego dotykania niczego
  • Klimatyzacja pracuje mniej (mniej promieniowania termicznego wchodzi przez okno; pomiar u mnie: -1,5 do -2°C latem w pomieszczeniu vs setup statyczny)
  • W salonie podczas filmu wieczorem (M_TV_MODE) tilt zamyka się na 80° automatycznie, gdy ktoś włącza HA scenę "kino"
  • Zimą algorytm jest odwrotny — gdy słońce świeci, otwiera się max (passive solar heating, zwykle +2-3°C w pomieszczeniu o 12:00 w styczniu)

Hardware pogodynki — co zbudować na dachu:

Najprostszy zestaw na ESP32 (Raspberry Pi też się nadaje, ale ESP32 wystarcza):

Czujnik Funkcja Cena
BH1750 Natężenie światła 1-65535 lx 8 zł
BMP280 Ciśnienie + temp 12 zł
DHT22 / SHT31 Wilgotność + temp 15-30 zł
Anemometr kubełkowy (impulsowy) Wiatr 0-30 m/s 80-120 zł
Deszczomierz tipping bucket Opady mm/h 50-100 zł
UV index (VEML6075) Indeks UV 25 zł
ESP32 + obudowa IP65 + zasilanie 24V→5V Sterownik 60 zł
Razem ~250-350 zł

Skrętka 4×2×0,5 mm² od dachu do szafy sterowniczej daje zasilanie + Modbus RS485 lub Ethernet (zależnie od konfigu). Jeśli na dachu jest miejsce w peszlu, dorzuć drugą skrętkę na zapas.

ESP32 publikuje do MQTT broker w domu (pogodynka/lux, pogodynka/wiatr, pogodynka/uv etc.), HA agreguje, oblicza orientację słońca przez sun.sun (wystarczy podać szerokość i długość w configuration.yaml) i wysyła do PLC docelowe wartości tilt+height przez Modbus.

Pomocniczy sygnał z pogodynki — automatyczne zamykanie przy burzy:

Killer feature, którego nie ogarniesz bez własnej pogodynki: gdy wiatr przekroczy 12 m/s (lub gradobicie wykryte z deszczomierza), PLC automatycznie:

  1. Wciąga wszystkie żaluzje fasadowe na 100% w górę (chowa, żeby wiatr nie urwał lameli)
  2. Zamyka markizy i wewnętrzne rolety okienne (ochrona przed gradem)
  3. Wysyła push do HA: "wykryta burza, schowano X żaluzji"

OpenWeatherMap też daje wiatromiar, ale opóźnienie do 30-60 minut. Własna pogodynka reaguje w 5 sekund. Jak był u nas w Wielkopolsce gradobicie w lipcu 2024, sąsiad miał 3 żaluzje do wymiany (12k zł). Moje schowały się 90 sekund przed pierwszą gradobicą — 0 zł szkód.

Pułapki, na które warto uważać:

  1. Hysteresis jest konieczna — bez niej algorytm w pochmurną pogodę będzie tańczyć tilt±15° co minutę. Serwomotor zżeresz w 6 miesięcy. Min 15 minut delay między zmianami + threshold |delta| > 5°
  2. User override — jeśli ktoś ręcznie ruszył tilt z poziomu HMI/przycisku, PLC wyłącza auto-correction dla tej rolety na 2 godziny (timer w PLC). Inaczej user kliknie "otwórz", PLC za 5 sekund "zamknij bo lux wysoki", user się wkurzy
  3. Detekcja "zachód słońca vs burza" — gdy lux spada z 50 klx do 1 klx, mogą to być dwa scenariusze. Klucz: sprawdź sun_elevation z HA — jeśli > 5° to chmura/burza (otwórz max, wykorzystaj resztki światła), jeśli < 5° to zachód (PLC wykonuje definitive close na noc, według timera + sunset)
  4. Konflikt z auto-kalibracją — sekcja powyżej. Auto-kalibracja resetuje pozycję na 0 nocą. Daylight harvesting nie może wystartować rano przed kalibracją. Solution: master state machine w PLC: IDLE → AUTOCALIB (03:15-03:45) → DAYTIME_HARVESTING (07:00-21:00) → EVENING_CLOSE (sunset) → NIGHT_IDLE → ...
  5. Wycieki ciepła zimą — w nocy w styczniu chcesz żaluzje zamknięte (dodatkowa warstwa izolacji, U-value spada z ~1,1 na ~0,8 W/m²K). Algorytm: o 18:00 zimą wszystkie żaluzje zamykają się max (tilt=90°, height=0%), niezależnie od auto-kalibracji
  6. Pomieszczenia z roślinami — szczególnie storczyki, kaktusy. M-flag "tu są rośliny" → minimum tilt 20° (zawsze wpuszczaj rozproszone światło)
  7. Sąsiad / prywatność — gdy słońce ma niski kąt (zachód, październik-marzec), tilt też kontroluje co widzą sąsiedzi. Lamela w pozycji "góra do wewnątrz" = nie widać do środka. M-flag "okno przylegające do działki sąsiada" → preferuj tilt-up nad tilt-down

Skutek użytkowy — i to jest dosłowny powód, czemu klienci zostają z tym systemem na lata:

"Pierwsze 2 tygodnie nie zauważasz że coś się dzieje. Po miesiącu odkrywasz, że nie pamiętasz kiedy ostatni raz dotknąłeś przycisku rolety. Po pół roku ktoś przychodzi do Ciebie i mówi 'kurde, w Twoim biurze jest jakoś tak miło' — i nie potrafi powiedzieć czemu."

To jest moment, kiedy automatyka staje się niewidzialna, a to jest jej ostateczny test.

Pytanie: kiedy MQTT, kiedy Modbus, kiedy bezpośrednia integracja

Liczba rolet Stack rekomendowany
1-3 Shelly Plus 2PM + native HA integration. Najprostsze, ZERO YAML
3-6 Supla / Shelly + MQTT (jak masz @martinsnow)
5-12 Wago / Siemens LOGO + Modbus TCP do HA
10+ Fatek FBs / Wago 750 + Modbus TCP + opcjonalnie HMI Weintek dla paneli ściennych

Próg "kiedy PLC" jest dyskusyjny, ale moim zdaniem przy 5-6 roletach robi się sensownie, przy 10+ jest oczywiste — bo skala kasetek przekaźnikowych, czas okablowania i koszt 10 sztuk Shelly Plus 2PM (≈1500-2000 zł) zbliżają się do ceny PLC, a uzyskujesz znacznie wyższą niezawodność i autonomię.


@martinsnow — fajnie że rozwiązanie zostawiłeś w wątku, to się bardzo przydaje. Pisz jakby kiedyś chciał pójść w stronę PLC + Modbus zamiast MQTT, bo jak masz Supla = masz dużo rolet = stack ESP czasem zaczyna zgrzytać przy 10+ urządzeniach. Trzymaj się.

Pozdrawiam, Darek (TechionGroup — automatyka PLC Fatek + HMI Weintek + SCADA + Home Assistant)


 
Dodane : 11/05/2026 9:13 pm
Udostępnij: