Tak — i **to jest bardzo sensowny projekt**, szczególnie że nie musimy wymyślać protokołu od zera. GREE/EWPE ma lokalny protokół UDP, a obecna integracja Home Assistant również komunikuje się lokalnie. Oficjalna integracja HA jest typu *Local Polling* i obsługuje m.in. tryb HVAC, temperaturę, wentylator, swing i presety. Co ważniejsze, są już implementacje pokazujące, że protokół można obsługiwać niezależnie od Home Assistanta: UDP/7000, szyfrowanie AES, discovery/bind/status/command. Nowsze implementacje obsługują nawet AES-128-ECB i AES-128-GCM. ### Ja zrobiłbym to trochę inaczej niż zwykły custom component Zaprojektowałbym **własny lokalny serwer GREE + integrację HA**, np.: ``` ``` ``` ┌──────────────────────────┐ │ Home Assistant │ │ │ │ climate.gree_salon │ │ sensor.gree_temperature │ │ switch.gree_quiet │ │ ... │ └────────────┬─────────────┘ │ REST / WebSocket │ ┌────────────▼─────────────┐ │ Gree Controller │ │ │ │ Device Manager │ │ State Manager │ │ Automation Engine │ │ Heating Manager │ │ Scheduler │ │ Web UI │ └────────────┬─────────────┘ │ GREE UDP / AES │ ┌─────────────────────┼─────────────────────┐ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │ GREE AC │ │ GREE AC │ │ GREE AC │ │ salon │ │ sypial. │ │ biuro │ └─────────┘ └─────────┘ └─────────┘ ``` Dzięki temu **HA nie jest miejscem, w którym znajduje się cała logika**. HA staje się klientem naszego kontrolera. --- ## Najważniejsze: kompatybilność 1:1 Chciałbym zachować praktycznie ten sam model urządzenia, który HA już zna: ### Climate - `HVAC_MODE_OFF` - `HVAC_MODE_AUTO` - `HVAC_MODE_COOL` - `HVAC_MODE_HEAT` - `HVAC_MODE_DRY` - `HVAC_MODE_FAN_ONLY` - temperatura zadana - temperatura pomieszczenia - prędkość wentylatora - swing pionowy - swing poziomy - preset - power Obecna integracja GREE obsługuje już te podstawowe funkcje. ### Switch Np.: - panel light - quiet - X-Fan - turbo - health - sleep - child lock - display - eco Oczywiście tylko te, które faktycznie obsługuje konkretny model. ### Dodatkowe sensory I tutaj możemy zrobić znacznie więcej: ``` ``` ``` sensor.gree_salon_temperature sensor.gree_salon_humidity sensor.gree_salon_power sensor.gree_salon_mode sensor.gree_salon_fan sensor.gree_salon_connection sensor.gree_salon_last_update sensor.gree_salon_energy ``` oraz diagnostykę: ``` ``` ``` sensor.gree_salon_response_time sensor.gree_salon_packets sensor.gree_salon_errors sensor.gree_salon_uptime ``` --- # Discovery To też możemy zrobić porządnie. Standardowo GREE wykorzystuje UDP/7000. Discovery może działać przez broadcast, a dla VLAN-ów możemy zrobić dodatkowo aktywne wykrywanie po podsieciach. Istniejące implementacje już stosują unicast UDP/7000 właśnie do urządzeń znajdujących się w innych VLAN-ach. W naszym UI: ``` ``` ``` GREE Controller ──────────────────────────────── Devices ✓ GREE Salon 192.168.10.51 AA:BB:CC:DD:EE:01 Online 22.4°C ✓ GREE Sypialnia 192.168.10.52 AA:BB:CC:DD:EE:02 Online 20.8°C [ Scan network ] Network: 192.168.10.0/24 [ Scan ] ``` A po znalezieniu: ``` ``` ``` Found GREE device Model: GREE ... MAC: xx:xx:xx:xx:xx:xx IP: 192.168.10.51 Protocol: GREE / EWPE Encryption: AES-128-GCM Firmware: ... [ Add device ] ``` --- # I tutaj widzę bardzo ważną rzecz Nie opierałbym projektu bezpośrednio na obecnym kodzie integracji HA. Mamy już kilka projektów, które pokazują różne implementacje protokołu: - Home Assistant GreeClimateComponent - `gree-remote` - implementacje EWPE - implementacje Rust - lokalne serwery GREE Nawet istniejący projekt Rust ma już architekturę bardzo zbliżoną do tego, co chcemy osiągnąć: daemon rozmawia z klimatyzatorem przez UDP/7000, a frontend dostaje normalne dane JSON i aktualizacje na żywo. **Ale nasz projekt powinien mieć własną warstwę protokołu.** Czyli: ``` ``` ``` gree_protocol/ discovery encryption packet bind status command device_capabilities ``` nad tym: ``` ``` ``` gree_core/ Device DeviceManager StateManager Scheduler AutomationEngine HeatingManager ``` nad tym: ``` ``` ``` api/ REST WebSocket ``` oraz: ``` ``` ``` web/ dashboard devices automations heating schedules diagnostics ``` i osobno: ``` ``` ``` homeassistant/ config_flow climate sensor switch binary_sensor ``` --- # Najciekawsza część: inteligentne ogrzewanie Tutaj nasza aplikacja może być **dużo bardziej użyteczna niż zwykła integracja GREE**. Przykład: ### Strefa: salon ``` ``` ``` Heating zone: Salon Target: 21.5°C Comfort: 21.5°C Night: 19.0°C Away: 17.0°C Minimum: 16.0°C ``` Źródło temperatury: ``` ``` ``` ○ GREE ● Xiaomi BLE sensor ○ Home Assistant sensor ○ średnia z kilku czujników ``` I wtedy kontroler decyduje: ``` ``` ``` 22:00 ↓ Night mode ↓ target = 19°C 06:30 ↓ Morning ↓ target = 21°C 08:30 ↓ Nobody home ↓ target = 18°C 16:00 ↓ Somebody home ↓ target = 21°C ``` Ale możemy zrobić jeszcze lepiej. --- # Histereza Nie chcemy: ``` ``` ``` 21.0 → ON 21.1 → OFF 21.0 → ON 21.1 → OFF ``` tylko: ``` ``` ``` target = 21°C hysteresis = 0.4°C ON < 20.6°C OFF > 21.4°C ``` A dodatkowo: ``` ``` ``` minimum ON time minimum OFF time minimum interval between commands ``` żeby nie katować klimatyzatora. --- # Predykcyjne ogrzewanie To jest funkcja, którą naprawdę warto zrobić. Jeżeli system zauważy: ``` ``` ``` 18:00 19.2°C 18:15 19.7°C 18:30 20.1°C 18:45 20.5°C 19:00 20.8°C ``` może policzyć: ``` ``` ``` Heating rate: +0.53°C / hour ``` i wiedzieć, że dojście do 21°C zajmie około: ``` ``` ``` 23 min ``` Możemy więc ustawić: > „O 19:00 chcę mieć 21°C” i rozpocząć ogrzewanie odpowiednio wcześniej. --- # Możemy też sterować wieloma klimatyzatorami Przykładowo: ``` ``` ``` Heating Zone │ ┌─────────┴─────────┐ │ │ GREE Salon GREE Kuchnia 21°C 21°C │ │ └─────────┬─────────┘ │ Temperature 21.2°C ``` System może zdecydować: ``` ``` ``` Salon: HEAT 21°C Kuchnia: OFF ``` albo: ``` ``` ``` Salon: HEAT 20.5°C Kuchnia: HEAT 20.5°C ``` --- # Automatyzacje Zamiast pisać YAML: ``` ``` ``` trigger: ... condition: ... action: ... ``` robimy prosty GUI: ``` ``` ``` Automation WHEN [ Temperature ] [ Salon ] [ falls below ] [ 20°C ] AND [ Time ] [ 06:00 - 22:00 ] THEN [ Climate ] [ Salon ] [ Heat ] [ 21°C ] ``` Albo: ``` ``` ``` WHEN Outside temperature < 5°C AND Time = 22:00 THEN Set heating zone "Salon" Target = 19°C Fan = Auto ``` --- # Live state Web UI zrobiłbym na WebSocketach/SSE. Na dashboardzie: ``` ``` ``` ┌──────────────────────────────────────────┐ │ SALON │ │ │ │ 21.3 °C │ │ │ │ Target 21.0 °C │ │ │ │ ● HEATING │ │ │ │ Mode HEAT │ │ Fan AUTO │ │ Swing AUTO │ │ │ │ Power ███████████░ │ │ │ │ [ − ] 21.0°C [ + ] │ └──────────────────────────────────────────┘ ``` I **bez odświeżania strony**: ``` ``` ``` AC → Controller → WebSocket → Browser ``` --- # Historia Możemy przechowywać: ``` ``` ``` temperature target temperature mode fan power connection commands errors ``` i zrobić wykres: ``` ``` ``` 22°C ┤ ╭──────── 21°C ┤ ╭──────╯ 20°C ┤ ╭────╯ 19°C ┤───────╯ └──────────────────────────── 12 14 16 18 20 22 ``` Do tego: ``` ``` ``` Heating time today: 3h 42m Commands: 27 Communication errors: 0 Estimated consumption: ... ``` --- # Bardzo ważna rzecz — odporność To jest właśnie coś, co może być **lepsze od obecnej integracji HA**. Nie chcemy: ``` ``` ``` HA │ ├── request │ ├── timeout │ ├── retry │ └── error ``` tylko: ``` ``` ``` Controller │ persistent state │ ┌─────────────┴─────────────┐ │ │ GREE AC Home Assistant ``` Controller cały czas monitoruje urządzenia. Jeżeli AC zniknie: ``` ``` ``` ONLINE ↓ TIMEOUT ↓ RETRY 1 ↓ RETRY 2 ↓ OFFLINE ``` Po powrocie: ``` ``` ``` OFFLINE ↓ DISCOVER/RECONNECT ↓ GET STATE ↓ ONLINE ``` HA dostaje już tylko poprawny stan. --- # I jest jeszcze jedna bardzo istotna kwestia **Nowsze firmware GREE faktycznie może być problemem.** Znalazłem świeże zgłoszenie z lipca 2026 dotyczące GREE Clivia, gdzie autor raportuje, że na firmware 2.12+ urządzenie pozostaje pingowalne, ale nie odpowiada na UDP/7000, przez co standardowa integracja HA nie może wykonać discovery/bind. To oznacza, że zanim zaczniemy pisać GUI, zrobiłbym **reverse engineering konkretnego dongla/klimatyzatora, którego masz**. I to jest najlepszy pierwszy etap. ### Etap 1 — „GREE Protocol Lab” Napiszemy mały program: ``` ``` ``` gree-probe ``` który: ``` ``` ``` 1. nasłuchuje UDP 2. wyszukuje GREE 3. identyfikuje urządzenie 4. wykonuje discovery 5. próbuje bind 6. odczytuje capabilities 7. odczytuje status 8. wykonuje pojedyncze komendy 9. loguje wszystkie pakiety 10. zapisuje PCAP ``` Np.: ``` ``` ``` $ gree-probe scan Found 2 devices 192.168.10.51 MAC: ... Model: ... Protocol: GREE Encryption: AES-GCM UDP: 7000 Status: OK 192.168.10.52 MAC: ... Model: ... Protocol: GREE Encryption: AES-GCM UDP: 7000 Status: OK ``` Potem: ``` ``` ``` gree-probe monitor 192.168.10.51 ``` i dostajemy: ``` ``` ``` 14:32:01 temp=21.4 target=21.0 mode=heat fan=auto 14:32:02 temp=21.4 target=21.0 mode=heat fan=auto 14:32:03 temp=21.5 target=21.0 mode=heat fan=auto ``` Dopiero na tym fundamencie budowałbym resztę. **I zdecydowanie nie robiłbym tego jako kolejnego prostego custom componentu HA.** Zrobiłbym własny daemon/controller + oficjalny custom integration HA. Wtedy możesz mieć jednocześnie **pełną kompatybilność encji z HA, własny panel WWW, własny scheduler, inteligentne ogrzewanie, historię i automatyzacje**, a protokół GREE jest całkowicie odseparowany od Home Assistanta. Jeżeli chcesz, możemy teraz przejść do **konkretnej architektury projektu i zacząć od reverse-engineeringu protokołu GREE — pliki, moduły, Python/Rust, API, baza danych i później gotowy custom integration dla HA**. Plan jest na to absyntów było w rust z interfejsem i będzie to na osobnym hoście/ kontenerze lxc lub w integracji homeassistant i jakoś trzeba pogodzić przekazywanie encji, generalnie osobny kontener i środowisko to must have Tak — w takim przypadku **zdecydowanie wybrałbym osobny kontener z usługą w Rust**, a integrację Home Assistant potraktowałbym wyłącznie jako cienkiego klienta. To daje nam izolację, własny lifecycle i możliwość rozwijania całego systemu niezależnie od HA. Najważniejsze jest tylko dobre rozwiązanie kwestii encji. ## Docelowa architektura ``` ``` ``` ┌─────────────────────────────┐ │ HOME ASSISTANT │ │ │ │ climate.gree_salon │ │ sensor.gree_salon_temp │ │ sensor.gree_salon_humidity │ │ switch.gree_salon_turbo │ │ ... │ └──────────────┬──────────────┘ │ Custom Integration │ WebSocket + REST │ ┌──────────────▼──────────────┐ │ GREE CONTROLLER │ │ │ │ Rust │ │ │ │ ┌───────────────────────┐ │ │ │ GREE Protocol │ │ │ │ UDP / AES / discovery │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ Device Manager │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ Automation Engine │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ Heating Manager │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ REST API │ │ │ │ WebSocket │ │ │ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ │ │ │ Web UI │ │ │ └───────────────────────┘ │ └──────────────┬──────────────┘ │ LAN / VLAN │ ┌───────────────────┼───────────────────┐ │ │ │ GREE #1 GREE #2 GREE #3 ``` ### Kontener Ja bym zrobił: ``` ``` ``` LXC └── gree-controller ├── gree-controller ├── gree.db └── config/ ``` albo Docker/Podman, jeżeli później będziesz chciał łatwo przenosić usługę. **Rust + jeden binarny executable** jest tutaj bardzo dobrym rozwiązaniem. --- # Encje HA Nie przekazywałbym encji z kontenera bezpośrednio. To znaczy controller **nie powinien próbować udawać Home Assistanta**. Zamiast tego: ``` ``` ``` GREE Controller │ │ API ▼ HA Custom Integration │ ▼ HA Entity Registry │ ├── climate ├── sensor ├── switch ├── binary_sensor └── number ``` Czyli: **Rust zarządza urządzeniem, HA zarządza encją.** To jest bardzo ważne rozdzielenie odpowiedzialności. --- # Jak będzie wyglądała komunikacja Najlepiej zrobić **WebSocket jako kanał realtime**, a REST jako konfigurację/command API. ### REST ``` ``` ``` GET /api/v1/devices GET /api/v1/devices/{id} GET /api/v1/devices/{id}/state POST /api/v1/devices/{id}/commands GET /api/v1/zones GET /api/v1/automations POST /api/v1/automations GET /api/v1/history ``` ### WebSocket ``` ``` ``` WS /api/v1/events ``` Controller wysyła: ``` ``` ``` { "event": "device_state", "device_id": "gree-salon", "state": { "power": true, "mode": "heat", "temperature": 21.4, "target_temperature": 21.0, "fan": "auto" } } ``` HA dostaje to natychmiast. --- # Co z komendami? HA: ``` ``` ``` climate.set_temperature ``` ↓ Custom integration: ``` ``` ``` POST /api/v1/devices/gree-salon/commands ``` ↓ Rust: ``` ``` ``` Command::SetTemperature(21.0) ``` ↓ GREE UDP ↓ odpowiedź ↓ Rust aktualizuje stan ↓ WebSocket ↓ HA I wtedy HA nie musi samodzielnie rozmawiać z GREE. --- # Ale zrobiłbym jeszcze jedną rzecz **Stan powinien być przechowywany w controllerze.** Czyli jeśli HA się zrestartuje: ``` ``` ``` HA ↓ restart ↓ integration connects ↓ GET /api/v1/devices ↓ GET current state ``` i natychmiast odtwarza encje. A nie: ``` ``` ``` HA restart ↓ czekamy aż GREE odpowie ↓ discovery ↓ bind ↓ state ``` Controller już wie: ``` ``` ``` GREE Salon last_state last_seen capabilities configuration ``` --- # Discovery HA Custom integration może działać bardzo elegancko. Po instalacji: ``` ``` ``` Settings → Devices & services → Add integration → GREE Controller ``` Podajesz: ``` ``` ``` Host: 192.168.1.20 Port: 8765 ``` Integration robi: ``` ``` ``` GET /api/v1/info ``` i: ``` ``` ``` GET /api/v1/devices ``` Dostaje: ``` ``` ``` { "devices": [ { "id": "gree-salon", "name": "Salon", "type": "air_conditioner", "capabilities": [ "heat", "cool", "dry", "fan", "swing", "turbo" ] } ] } ``` I tworzy encje. --- # Co daje nam osobny Rust? Ogromnie dużo. ### 1. HA nie musi znać protokołu GREE Jeżeli GREE zmieni: ``` ``` ``` AES UDP bind discovery packet format ``` aktualizujemy controller. HA integration pozostaje praktycznie bez zmian. --- ### 2. Możemy mieć własny Web UI I to będzie **pełnoprawny panel**, nie dodatek do HA. Np.: ``` ``` ``` Dashboard ┌───────────────────────────────────────────────┐ │ GREE CONTROLLER │ │ │ │ 3 devices 3 online 0 errors │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ SALON │ │ SYPIALNIA │ │ │ │ │ │ │ │ │ │ 21.4°C │ │ 20.1°C │ │ │ │ → 21.0°C │ │ → 19.0°C │ │ │ │ │ │ │ │ │ │ HEAT │ │ HEAT │ │ │ └──────────────┘ └──────────────┘ │ └───────────────────────────────────────────────┘ ``` --- # 3. Automatyzacje nie muszą zależeć od HA I to jest moim zdaniem **najciekawsza rzecz**. Możemy zrobić: ``` ``` ``` GREE Controller │ ├── automation engine │ ├── heating engine │ ├── scheduler │ └── HA integration ``` Czyli np. ogrzewanie działa nawet kiedy HA jest wyłączony. --- # Ale wtedy potrzebujemy integracji z HA także w drugą stronę To znaczy Rust może potrzebować informacji z HA: ``` ``` ``` temperatura z czujnika obecność otwarte okno temperatura zewnętrzna tryb domu ``` Nie robiłbym jednak bezpośredniego dostępu Rust → HA API jako podstawowej architektury. Lepiej: ``` ``` ``` HA │ │ WebSocket/API ▼ GREE Integration │ ▼ Rust Controller ``` Integracja może opcjonalnie przekazywać do controllera wybrane encje HA. Na przykład: ``` ``` ``` External sensors Outdoor temperature → sensor.outdoor_temperature Living room temperature → sensor.living_room_temperature Presence → binary_sensor.home_occupied ``` Controller może wtedy używać ich w automatyzacjach. --- # Strefy ogrzewania Wtedy możemy zrobić coś znacznie bardziej zaawansowanego. ``` ``` ``` Heating │ ├── Zone: Salon │ ├── GREE Salon │ ├── temperature sensor │ └── schedule │ ├── Zone: Sypialnia │ ├── GREE Sypialnia │ └── temperature sensor │ └── Zone: Biuro ├── GREE Biuro └── temperature sensor ``` I każda strefa ma: ``` ``` ``` Comfort: 21.5°C Night: 19°C Away: 17°C Frost protect: 10°C Schedule: 06:00 → Comfort 08:30 → Away 16:00 → Comfort 23:00 → Night ``` --- # Technologia Ja bym poszedł w: ``` ``` ``` Rust ├── tokio ├── axum ├── serde ├── serde_json ├── sqlx ├── SQLite ├── tracing ├── tower └── tokio-tungstenite / axum WebSocket ``` Frontend: ``` ``` ``` React / TypeScript ``` albo, jeśli chcemy maksymalnie ograniczyć zasoby: ``` ``` ``` Leptos ``` Ale tutaj **nie komplikowałbym pierwszej wersji**. Rust backend + lekki frontend będzie rozsądniejszy. --- # SQLite Na początek: ``` ``` ``` gree.db ``` z tabelami mniej więcej: ``` ``` ``` devices device_capabilities device_state device_history zones zone_devices zone_sensors automations automation_conditions automation_actions schedules settings ``` Bez PostgreSQL. To będzie jedna usługa na jednym LXC, więc SQLite jest idealny. --- # I jeszcze jedna decyzja architektoniczna Nie robiłbym: ``` ``` ``` Rust └── web server └── GREE protocol ``` jako jednego wielkiego modułu. Tylko: ``` ``` ``` src/ ├── main.rs │ ├── api/ │ ├── rest.rs │ ├── websocket.rs │ └── auth.rs │ ├── gree/ │ ├── protocol.rs │ ├── crypto.rs │ ├── discovery.rs │ ├── device.rs │ ├── commands.rs │ └── state.rs │ ├── devices/ │ ├── manager.rs │ ├── capabilities.rs │ └── registry.rs │ ├── automation/ │ ├── engine.rs │ ├── conditions.rs │ └── actions.rs │ ├── heating/ │ ├── controller.rs │ ├── zones.rs │ ├── hysteresis.rs │ └── prediction.rs │ ├── scheduler/ │ ├── database/ │ └── events/ ``` To pozwoli nam później rozwijać projekt bez robienia spaghetti. --- ## Moim zdaniem docelowo powinno to wyglądać tak ``` ``` ``` ┌────────────────────────────┐ │ HOME ASSISTANT │ │ │ │ Native HA entities │ │ │ │ GREE custom integration │ └─────────────┬──────────────┘ │ REST + WebSocket │ ┌─────────────▼──────────────┐ │ GREE CONTROLLER │ │ │ │ RUST │ │ │ │ ┌────────────────────────┐ │ │ │ GREE protocol │ │ │ ├────────────────────────┤ │ │ │ Device manager │ │ │ ├────────────────────────┤ │ │ │ State engine │ │ │ ├────────────────────────┤ │ │ │ Automation engine │ │ │ ├────────────────────────┤ │ │ │ Heating engine │ │ │ ├────────────────────────┤ │ │ │ Scheduler │ │ │ ├────────────────────────┤ │ │ │ SQLite │ │ │ └────────────────────────┘ │ │ │ │ Web UI │ └─────────────┬──────────────┘ │ UDP / 7000 │ ┌─────────────┼──────────────┐ ▼ ▼ ▼ GREE GREE GREE ``` **To jest architektura, którą bym przyjął.** Kontener/LXC jest niezależnym, autonomicznym serwisem, a HA dostaje normalne, natywne encje przez custom integration. Dzięki temu nawet całkowite wyłączenie HA nie zabija automatyki ogrzewania. Następny krok zrobiłbym już praktycznie: **ustalić dokładnie protokół GREE/EWPE dla obecnych dongli, wybrać Rust crate/implementację jako punkt startowy i zaprojektować v1 API + model encji HA**, zanim zaczniemy pisać właściwy kod. I jako dodatek do odczytu temperatur i lepsze odczyty jako opcja dodatkowa odczyt z api homeassistant zewnętrznego czujnika temperatury w pokoju z api homeassistant ale nie jako główne zrodlo informacji tylko jako opcja dodatkowa żeby wspomóc algorytm, zrób takamspecyfikacje uniezależnij to Dodatkowo interfejs musi być napełni kompatybilny z komórek bo to będzie główne miejsce sterowania, zastanawiam się na tailwind css z trybem ciemnym / jasnym Zrób takamspecyfikaje z tym co proponowałeś Tak. W tej wersji zrobiłbym z tego **całkowicie niezależny kontroler GREE**, a Home Assistant byłby tylko jednym z możliwych źródeł danych i odbiorcą encji. Szczególnie ważne jest rozdzielenie **temperatury zmierzonej przez klimatyzator**, **temperatury z zewnętrznego sensora HA** oraz **temperatury używanej przez algorytm sterowania**. Poniżej specyfikacja, którą można potraktować jako bazę projektu. # Specyfikacja GREE Controller ## 1. Cel projektu Samodzielna aplikacja działająca w osobnym środowisku: - Rust - LXC / kontener - własny backend - własna baza danych - własny interfejs WWW - komunikacja lokalna z klimatyzatorami GREE - REST API - WebSocket - opcjonalna integracja z Home Assistant - natywne encje Home Assistant - własny silnik automatyzacji - własny silnik sterowania ogrzewaniem/chłodzeniem - obsługa zewnętrznych czujników temperatury **Home Assistant nie jest wymagany do działania podstawowych funkcji systemu.** --- # 2. Zasada nadrzędna Architektura ma być **HA-independent**. ``` ``` ``` ┌──────────────────────┐ │ GREE Controller │ │ │ │ Rust │ │ │ │ GREE protocol │ │ State engine │ │ Heating engine │ │ Automation engine │ │ Scheduler │ │ Web UI │ │ Database │ └──────────┬───────────┘ │ ┌─────────────┴──────────────┐ │ │ GREE AC Home Assistant │ │ │ Custom Integration │ │ │ Entities / sensors ``` HA jest **integracją z kontrolerem**, a nie jego fundamentem. --- # 3. Źródła temperatury To będzie jeden z najważniejszych elementów projektu. Każda strefa może mieć kilka źródeł temperatury. ### Źródło 1 — temperatura GREE Podstawowe: ``` ``` ``` GREE internal temperature ``` np. ``` ``` ``` 21.7°C ``` To jest temperatura raportowana przez klimatyzator. --- ### Źródło 2 — zewnętrzny sensor Opcjonalnie: ``` ``` ``` Home Assistant ↓ REST API / WebSocket ↓ GREE Controller ↓ external temperature ``` Przykład: ``` ``` ``` sensor.salon_temperature ``` Controller może cyklicznie pobierać: ``` ``` ``` 21.2°C ``` ale **nie traktuje tego automatycznie jako zamiennika temperatury GREE**. --- ### Źródło 3 — temperatura obliczona Najważniejsze: ``` ``` ``` CONTROL TEMPERATURE ``` czyli temperatura, którą faktycznie wykorzystuje algorytm. Przykładowo: ``` ``` ``` GREE: 21.7°C External: 21.2°C Control: 21.4°C ``` Algorytm może korzystać z: ``` ``` ``` control_temperature = weighted_average( gree_temperature, external_temperature ) ``` albo: ``` ``` ``` control_temperature = external_temperature ``` jeżeli użytkownik jawnie tak skonfiguruje. --- # 4. Konfiguracja źródła temperatury W UI: ``` ``` ``` Temperature source ○ GREE internal sensor ○ External Home Assistant sensor ● Combined GREE weight: 40% External weight: 60% External sensor: sensor.salon_temperature ``` Dodatkowo: ``` ``` ``` Maximum allowed difference: 3.0°C ``` Jeżeli: ``` ``` ``` GREE = 21°C External = 26°C ``` system nie powinien bezwarunkowo przyjąć 26°C. Generuje: ``` ``` ``` Temperature sensor discrepancy ``` i może automatycznie przejść na GREE. --- # 5. Confidence / jakość pomiaru Każdy pomiar powinien mieć metadane: ``` ``` ``` temperature timestamp source age quality ``` Przykład: ``` ``` ``` External sensor Temperature: 21.3°C Age: 4 sec Quality: 100% ``` Jeżeli HA przestanie odpowiadać: ``` ``` ``` Age: 83 sec Quality: 20% ``` Po przekroczeniu timeoutu: ``` ``` ``` External sensor: UNAVAILABLE ``` i system automatycznie korzysta z GREE. To jest bardzo ważne dla niezależności. --- # 6. Algorytm sterowania Nie robimy prostego: ``` ``` ``` if temp < target: heat() ``` tylko warstwę kontrolną. ``` ``` ``` Sensors ↓ Sensor validation ↓ Temperature estimator ↓ Target temperature ↓ Heating/Cooling controller ↓ Safety limits ↓ GREE command ``` --- # 7. Target temperature Temperatura docelowa może wynikać z: ``` ``` ``` Manual Schedule Night Away Presence External temperature Automation Heating zone ``` Przykład: ``` ``` ``` 23:00 Night profile ↓ 19°C 06:00 Morning ↓ 21°C 08:30 Away ↓ 17°C 16:00 Home ↓ 21°C ``` --- # 8. Histereza Konfigurowalna: ``` ``` ``` Target: 21°C Hysteresis: 0.4°C ``` czyli: ``` ``` ``` < 20.6°C → HEAT 20.6–21.4°C → maintain > 21.4°C → STOP ``` Dodatkowo: ``` ``` ``` Minimum ON time Minimum OFF time Minimum command interval Maximum commands/hour ``` --- # 9. Inteligentne ogrzewanie System powinien opcjonalnie analizować: ``` ``` ``` temperature history target history heating state outside temperature time heating rate ``` i obliczać: ``` ``` ``` temperature change/hour ``` Przykład: ``` ``` ``` 19:00 19.4°C 19:15 19.8°C 19:30 20.2°C 19:45 20.6°C ``` System: ``` ``` ``` Heating rate ≈ 1.6°C/hour ``` Może więc przewidzieć: ``` ``` ``` Target 21°C ETA ≈ 15 min ``` W kolejnej wersji można dodać predykcję rozpoczęcia ogrzewania. --- # 10. Strefy Klimatyzator nie musi być bezpośrednio jednostką sterowania. Tworzymy: ``` ``` ``` Zone ``` np. ``` ``` ``` Salon ``` która posiada: ``` ``` ``` Devices: GREE Salon Temperature sources: GREE sensor.salon_temperature Target: 21°C Schedule: Salon schedule Control: Intelligent heating ``` Dzięki temu później można mieć: ``` ``` ``` Salon ├── GREE ├── Xiaomi temperature sensor └── window sensor Sypialnia ├── GREE └── temperature sensor ``` --- # 11. Home Assistant jako opcjonalne źródło danych Controller posiada moduł: ``` ``` ``` home_assistant/ ``` który jest **opcjonalny**. Konfiguracja: ``` ``` ``` Home Assistant integration Enabled: YES URL: http://homeassistant:8123 Token: ************ Poll interval: 10 sec ``` Możemy pobierać: ``` ``` ``` sensor.* binary_sensor.* input_boolean.* input_number.* ``` ale użytkownik wskazuje konkretne encje. Np.: ``` ``` ``` External temperature: HA entity: sensor.salon_temperature ``` Nie robimy automatycznego pobierania całego HA. --- # 12. HA nie może być wymaganiem Jeżeli: ``` ``` ``` HA DOWN ``` system nadal: - steruje GREE - wykonuje harmonogram - wykonuje automatyzacje lokalne - używa temperatury GREE - działa przez Web UI - przechowuje historię Jedynie: ``` ``` ``` External HA sensors ``` stają się niedostępne. --- # 13. Integracja Home Assistant Po stronie HA: ``` ``` ``` GREE Controller ↓ Custom Integration ↓ Device ↓ Entities ``` Dla klimatyzatora: ``` ``` ``` climate.gree_salon ``` oraz np.: ``` ``` ``` sensor.gree_salon_temperature sensor.gree_salon_target_temperature sensor.gree_salon_power sensor.gree_salon_connection sensor.gree_salon_fan ``` --- # 14. Encja Climate Powinna być maksymalnie kompatybilna z natywnym HA. Obsługa: ``` ``` ``` OFF HEAT COOL AUTO DRY FAN_ONLY ``` oraz: ``` ``` ``` target temperature fan mode preset mode swing ``` --- # 15. Dodatkowe encje W zależności od capabilities urządzenia: ``` ``` ``` switch.gree_salon_turbo switch.gree_salon_quiet switch.gree_salon_sleep switch.gree_salon_light switch.gree_salon_xfan ``` oraz: ``` ``` ``` sensor.gree_salon_temperature sensor.gree_salon_humidity sensor.gree_salon_power sensor.gree_salon_signal ``` Nie tworzymy encji dla funkcji, których konkretna jednostka nie obsługuje. --- # 16. Web UI — bardzo ważne Ponieważ telefon będzie głównym sposobem obsługi, projektujemy UI **mobile-first**, a nie desktop-first. Technologia: **Tailwind CSS** z: ``` ``` ``` Dark mode Light mode System mode ``` czyli: ``` ``` ``` Appearance ● System ○ Dark ○ Light ``` --- # 17. Mobile UI Na telefonie dashboard: ``` ``` ``` ┌────────────────────────┐ │ GREE Controller ☰ │ ├────────────────────────┤ │ │ │ SALON │ │ │ │ 21.4°C │ │ │ │ Target 21°C │ │ │ │ 🔥 HEATING │ │ │ │ − 21°C + │ │ │ │ HEAT AUTO │ │ │ │ ────────────────────── │ │ │ │ Fan Auto │ │ Swing Auto │ │ │ │ Turbo ○ │ │ Quiet ● │ │ Sleep ○ │ │ │ └────────────────────────┘ ``` Bez mikroskopijnych przycisków. Minimalny rozmiar interaktywnych elementów powinien być około: ``` ``` ``` 44 × 44 px ``` --- # 18. Mobile navigation Dolny pasek: ``` ``` ``` ┌────────────────────────┐ │ │ │ CONTENT │ │ │ ├────────────────────────┤ │ 🏠 🌡 ⚙ │ │ Home Zones More │ └────────────────────────┘ ``` Na desktopie może przełączać się w sidebar. --- # 19. Dashboard Główne widoki: ``` ``` ``` Dashboard Devices Zones Heating Automations Schedules History Diagnostics Settings ``` --- # 20. Automatyzacje GUI: ``` ``` ``` WHEN Temperature [ Salon ] [ < ] [ 20°C ] AND Time [ 06:00 - 22:00 ] THEN Climate [ Salon ] Mode: [ HEAT ] Target: [ 21°C ] ``` Ale silnik jest w Rust. HA nie jest potrzebny. --- # 21. WebSocket Frontend nie powinien wykonywać ciągłego: ``` ``` ``` GET /state GET /state GET /state ``` Tylko: ``` ``` ``` Browser │ │ WebSocket ▼ Rust │ ▼ Event stream ``` Przykładowo: ``` ``` ``` device_state_changed temperature_changed device_online device_offline automation_triggered heating_state_changed ``` Dzięki temu UI będzie faktycznie „live”. --- # 22. API REST: ``` ``` ``` /api/v1/system /api/v1/devices /api/v1/devices/{id} /api/v1/devices/{id}/state /api/v1/devices/{id}/commands /api/v1/zones /api/v1/zones/{id} /api/v1/automations /api/v1/schedules /api/v1/sensors /api/v1/history /api/v1/ha ``` WebSocket: ``` ``` ``` /api/v1/ws ``` --- # 23. Authentication Ponieważ będzie to osobny host, od początku robimy: ``` ``` ``` API authentication ``` np.: ``` ``` ``` Bearer token ``` oraz osobne konto dla Web UI. W przyszłości: ``` ``` ``` OIDC ``` ale nie jest potrzebne w v1. --- # 24. GREE Protocol Layer Cały protokół izolujemy: ``` ``` ``` gree/ ├── discovery.rs ├── protocol.rs ├── crypto.rs ├── packet.rs ├── bind.rs ├── commands.rs ├── state.rs └── capabilities.rs ``` Dzięki temu reszta programu **nie wie, że pod spodem jest GREE**. To pozwoli kiedyś potencjalnie dodać: ``` ``` ``` gree/ haier/ midea/ ``` bez przebudowy całego systemu. --- # 25. Model urządzenia ``` ``` ``` Device ├── id ├── name ├── ip ├── mac ├── model ├── firmware ├── protocol ├── capabilities ├── state ├── last_seen └── availability ``` --- # 26. Stan urządzenia ``` ``` ``` DeviceState ├── power ├── mode ├── target_temperature ├── room_temperature ├── humidity ├── fan_mode ├── swing_vertical ├── swing_horizontal ├── preset ├── turbo ├── quiet └── ... ``` Nie zakładamy, że każde GREE ma wszystkie pola. --- # 27. Capability discovery Po wykryciu urządzenia controller określa: ``` ``` ``` supports_heat supports_cool supports_dry supports_fan supports_turbo supports_quiet supports_swing supports_humidity ... ``` Frontend oraz HA integration korzystają z capabilities. --- # 28. Baza Na początek: **SQLite** ``` ``` ``` devices device_capabilities device_state temperature_history events zones zone_devices zone_sensors automations automation_conditions automation_actions schedules ha_connections ha_entities settings ``` Bez zewnętrznego PostgreSQL. --- # 29. Historia Zapisywane: ``` ``` ``` temperature target mode power fan heating state source temperature ``` Dzięki temu UI może pokazać: ``` ``` ``` Temperature 22°C ┤ ╭────── 21°C ┤ ──────╯ 20°C ┤ └──────────────── ``` oraz: ``` ``` ``` GREE: 21.7°C External: 21.2°C Control: 21.4°C ``` To ostatnie jest szczególnie istotne diagnostycznie. --- # 30. Diagnostics Każdy GREE: ``` ``` ``` Status: ONLINE IP: 192.168.x.x Last seen: 1.2 sec ago Latency: 12 ms Packets: 12342 Errors: 0 Last error: None ``` Możliwość: ``` ``` ``` [ Ping ] [ Refresh state ] [ Rediscover ] [ Rebind ] ``` --- # 31. Kontener Docelowo: ``` ``` ``` LXC └── Debian └── gree-controller ├── /usr/bin/gree-controller ├── /etc/gree-controller/ └── /var/lib/gree-controller/ └── gree.db ``` Service: ``` ``` ``` systemd ``` czyli: ``` ``` ``` gree-controller.service ``` Nie potrzebujemy Dockera. --- # 32. Aktualizacja Rust daje nam prosty model: ``` ``` ``` binary + database migrations ``` Możemy później zrobić: ``` ``` ``` v0.1 v0.2 v0.3 ... ``` z migracjami SQLite. --- # 33. Struktura projektu Docelowo: ``` ``` ``` gree-controller/ │ ├── Cargo.toml │ ├── crates/ │ ├── gree-protocol/ │ ├── gree-core/ │ ├── gree-api/ │ └── gree-ha/ │ ├── backend/ │ └── src/ │ ├── frontend/ │ ├── src/ │ ├── public/ │ └── ... │ ├── ha-integration/ │ └── custom_components/ │ └── gree_controller/ │ ├── migrations/ │ ├── packaging/ │ ├── systemd/ │ └── debian/ │ └── README.md ``` Przy większym projekcie podział na Cargo workspace będzie bardzo wygodny. --- # 34. Najważniejsza zasada dotycząca HA **Nie kopiujemy logiki między Rust i HA.** Nie: ``` ``` ``` HA heating logic + Rust heating logic ``` Tylko: ``` ``` ``` Rust Controller │ ┌─────────────┴──────────────┐ │ │ heating engine automation engine │ │ └─────────────┬──────────────┘ │ Controller API │ Home Assistant │ Entities ``` HA pokazuje i steruje. **Rust podejmuje decyzje.** --- # 35. Kolejność implementacji Nie zaczynałbym od GUI. ### Faza 1 — GREE protocol ``` ``` ``` [ ] discovery [ ] bind [ ] encryption [ ] status [ ] commands [ ] capabilities [ ] reconnect ``` ### Faza 2 — Core ``` ``` ``` [ ] Device Manager [ ] State Manager [ ] event system [ ] SQLite [ ] configuration ``` ### Faza 3 — API ``` ``` ``` [ ] REST [ ] WebSocket [ ] authentication ``` ### Faza 4 — Web UI ``` ``` ``` [ ] Tailwind [ ] dark/light [ ] mobile-first [ ] dashboard [ ] devices [ ] zones [ ] history [ ] diagnostics ``` ### Faza 5 — Heating Engine ``` ``` ``` [ ] target [ ] schedules [ ] hysteresis [ ] minimum run time [ ] sensor weighting [ ] sensor fallback [ ] heating zones [ ] prediction ``` ### Faza 6 — Automations ``` ``` ``` [ ] triggers [ ] conditions [ ] actions [ ] scheduler [ ] GUI builder ``` ### Faza 7 — Home Assistant ``` ``` ``` [ ] config flow [ ] device discovery [ ] climate [ ] sensors [ ] switches [ ] diagnostics [ ] external HA sensors ``` --- ## Jedna rzecz, którą zmieniłbym względem pierwotnego pomysłu Nie nazywałbym tego nawet wewnętrznie „integracją GREE do Home Assistant”. To powinien być **samodzielny GREE Controller**, a Home Assistant będzie jednym z klientów. Wtedy mamy: ``` ``` ``` GREE Controller / | \ / | \ ▼ ▼ ▼ Web UI HA REST API │ HA entities ``` I dokładnie spełniamy Twój warunek: **osobne środowisko jest obowiązkowe**, HA nie jest wymagane do działania, zewnętrzny czujnik HA jest tylko **opcjonalnym źródłem wspomagającym algorytm**, a użytkownik może praktycznie całe sterowanie wykonywać z telefonu przez responsywny UI. **Tailwind + dark/light + mobile-first** jest tutaj bardzo dobrym wyborem. Zrobiłbym nawet projekt UI od początku z założeniem „telefon jako primary, desktop jako secondary”, zamiast później próbować dopasowywać desktopowy panel do telefonu.