Files
gree-controller/docs/original-spec.md
T
2026-08-23 21:34:07 +02:00

47 KiB
Raw Blame History

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.621.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.