# Hladinovač kondenzu klimatizácie

Projekt monitoruje naplnenie nádržky na kondenz z klimatizácie a posiela upozornenia cez Telegram. Je určený pre situácie, kde kondenz neodteká priamo do odpadu, ale zbiera sa do nádoby, ktorú treba včas vyprázdniť.

## Účel projektu

Klimatizácia pri chladení produkuje kondenz. Ak sa kondenz zbiera do nádoby, pri pretečení môže zatiecť balkón, fasáda alebo interiér. Hladinovač vznikol ako jednoduché domáce riešenie, ktoré priebežne kontroluje stav nádržky a upozorní, keď sa hladina zmení alebo keď meranie prestane posielať dáta.

Meranie funguje pomocou vodivých elektród umiestnených v rôznych výškových úrovniach nádoby. Spoločná elektróda sa počas merania pripojí na logickú jednotku a jednotlivé hladinové elektródy sa čítajú ako digitálne vstupy. Ak voda dosiahne konkrétnu elektródu, uzavrie elektrický kontakt cez kondenz a daná úroveň sa vyhodnotí ako aktívna.

Použité sú 4 úrovne hladiny, pretože poskytujú dostatočne praktické rozlíšenie bez zložitého analógového merania:

- `level1` signalizuje približne 25 %.
- `level2` signalizuje približne 50 %.
- `level3` signalizuje približne 75 %.
- `level4` signalizuje plnú nádržku, teda 100 %.

## Architektúra riešenia

Systém je rozdelený na malú meraciu jednotku a serverovú časť.

- ESP8266/ESP32 zariadenie: číta hladinové elektródy, pripája sa na WiFi a posiela meranie na server.
- Snímače hladiny: vodivé kontakty v nádobe, jedna spoločná elektróda a štyri hladinové elektródy.
- WiFi komunikácia: zariadenie posiela hodnoty `level1..level4` cez HTTPS `POST`.
- Serverová časť: `server/log.php` prijme meranie, validuje vstup, uloží záznam a vyhodnotí notifikácie.
- Ukladanie meraní: každé meranie sa zapisuje ako jeden JSON riadok do súboru `data/YYYY.jsonl`.
- Telegram notifikácie: server posiela správy používateľom `igor` a `veronika` cez helper `telegram()` v `server/functions.inc.php`.

Tok dát:

```text
Senzory hladiny
       ↓
 ESP8266
       ↓
 HTTP POST
       ↓
 server/log.php
       ↓
 JSONL logy
       ↓
 Notifikácie
```

## Meranie hladiny

Jednotlivé levely predstavujú štvrtiny výšky nádoby.

| Level  | Význam |
| ------ | ------ |
| level1 | 25 %   |
| level2 | 50 %   |
| level3 | 75 %   |
| level4 | 100 %  |

Platné stavy hladiny:

```text
0000 = 0 %
1000 = 25 %
1100 = 50 %
1110 = 75 %
1111 = 100 %
```

Percento sa počíta podľa najvyššej dosiahnutej súvislej úrovne. Napríklad stav `1100` znamená, že voda dosiahla `level1` a `level2`, ale ešte nedosiahla `level3`, preto je nádržka na 50 %.

## Ochranné mechanizmy

Projekt obsahuje viac ochrán, aby neposielal zavádzajúce správy a aby bolo vidieť aj zlyhanie samotného monitorovania.

### Kontrola neplatných kombinácií hladín

Vyšší level nemôže byť aktívny, ak niektorý nižší level pod ním aktívny nie je. Voda sa v nádobe fyzicky nemôže dotýkať hornej elektródy bez toho, aby sa dotýkala nižšej elektródy.

Neplatné stavy sú napríklad:

```text
0100 = level2 je aktívny, ale level1 nie
1010 = level3 je aktívny, ale level2 nie
1101 = level4 je aktívny, ale level3 nie
```

Pri zistení takéhoto stavu `server/log.php` pošle Telegram upozornenie s konkrétnymi hodnotami levelov. Chyba pri odoslaní Telegram správy nezastaví uloženie merania ani nespôsobí HTTP chybu.

### Notifikácie iba pri zmene stavu

Notifikácia sa neposiela pri každom meraní. Server najprv porovná aktuálne uložený záznam s predchádzajúcim záznamom v JSONL súbore. Ak sa hodnoty `level1..level4` nezmenili, neodošle sa žiadna správa.

Tým sa zabraňuje spamovaniu Telegramu. Pri stabilnej hladine môže zariadenie posielať merania každých 30 minút, ale používateľ dostane správu iba vtedy, keď sa hladina reálne zmení.

### Kontrola výpadku monitorovania

Skript `server/data-checker.php` je určený na spúšťanie z CRON-u každú hodinu. Kontroluje posledné prijaté meranie v aktuálnom súbore `data/YYYY.jsonl`.

Logika je:

- Ak posledné meranie je mladšie ako 45 minút, všetko je v poriadku a skript nič neposiela.
- Ak posledné meranie je staršie ako 45 minút, ale mladšie ako 3 hodiny a 45 minút, pošle upozornenie.
- Ak posledné meranie je staršie ako 3 hodiny a 45 minút, neposiela už nič.

Pri hodinovom CRON-e to znamená najviac 3 upozornenia po výpadku merania. Dôvod je praktický: ak je senzor alebo klimatizácia vedome vypnutá, stačí dostať niekoľko upozornení a potom už nemá zmysel posielať každú hodinu ďalšiu správu bez zásahu do servera.

Skript je odolný voči bežným problémom:

- Ak dátový súbor neexistuje alebo je prázdny, ticho skončí.
- Ak posledný riadok nie je validný JSON, hľadá najbližší predchádzajúci validný riadok.
- Chyby pri Telegram odoslaní sú zachytené a zapísané cez `error_log()`.

## Telegram notifikácie

Príklady bežných správ pri zmene hladiny:

```text
Nádržka kondenzu klimatizácie: 25%
```

```text
Nádržka kondenzu klimatizácie: 75%
```

Príklad upozornenia na neplatnú kombináciu hladín:

```text
Chyba merania hladiny kondenzátu klimatizácie (level1=1, level2=0, level3=1, level4=0)
```

Príklad upozornenia na výpadok monitorovania:

```text
Nebola zaznamenaná nová hodnota hladiny kondenzu, posledná získaná hodnota je z 2026-06-24 11:30:00 (level1=1, level2=1, level3=0, level4=0). Toto upozornenie príde len 3x, potom sa už nekontroluje.
```

## Ukladanie dát

Merania sa ukladajú vo formáte JSONL, teda JSON Lines. Každý riadok je samostatný JSON objekt a predstavuje jedno meranie.

Príklad súboru:

```text
data/2026.jsonl
```

Ukážka obsahu:

```jsonl
{"timestamp":"2026-06-24T09:00:00+02:00","level1":0,"level2":0,"level3":0,"level4":0}
{"timestamp":"2026-06-24T09:30:00+02:00","level1":1,"level2":0,"level3":0,"level4":0}
{"timestamp":"2026-06-24T10:00:00+02:00","level1":1,"level2":1,"level3":0,"level4":0}
```

JSONL bol zvolený preto, že sa jednoducho dopisuje na koniec súboru, dá sa ľahko čítať po riadkoch a pri poškodení jedného riadku zostávajú ostatné záznamy čitateľné. Súbory sú rozdelené podľa rokov, aby jeden log nerástol donekonečna a aby sa dali staršie dáta jednoducho archivovať.

## Hardvér

Informácie nižšie sú z aktuálneho Arduino sketchu `arduino/arduino.ino`.

| Funkcia | GPIO | Označenie na NodeMCU | Poznámka |
| ------- | ---- | -------------------- | -------- |
| Spoločná elektróda | GPIO13 | D7 | Zapína sa iba počas merania |
| level1 | GPIO5 | D1 | Najnižšia hladina, 25 % |
| level2 | GPIO4 | D2 | 50 % |
| level3 | GPIO14 | D5 | 75 % |
| level4 | GPIO12 | D6 | Najvyššia hladina, 100 % |

ESP8266 verzia používa externé pull-down rezistory z každého level vstupu na `GND`. Pri ESP32 sketch nastavuje vstupy ako `INPUT_PULLDOWN`.

Spoločná elektróda je napájaná iba počas samotného merania. V kóde sa zapne, počká sa `50 ms` na ustálenie a potom sa prečítajú všetky štyri levely. Po meraní sa spoločná elektróda vypne, aby sa znížila korózia elektród.

Zariadenie v produkčnom režime (`DEBUG == 0`) po meraní odošle HTTP `POST`, vypne WiFi a prejde do deep sleep režimu. Interval spánku je `1800` sekúnd, teda 30 minút.

Napájanie nie je v kóde pevne definované. Použité ESP8266/ESP32 zariadenie treba napájať podľa konkrétnej dosky, typicky cez USB alebo stabilizovaný vstup dosky. Logické GPIO piny pracujú s 3,3 V úrovňami.

## Ilustračné fotografie

![Celkový pohľad na nádobu a elektroniku](docs/IMG_20260624_113621.jpg)

*Celkový pohľad na zbernú nádobu kondenzu, prívodnú hadicu a krabičku s elektronikou vedľa nádoby.*

![Krabička s elektronikou](docs/IMG_20260624_113628.jpg)

*Detail ochrannej krabičky s ESP doskou a prepojovacími vodičmi.*

![Vodivé elektródy v hrdle nádoby](docs/IMG_20260624_113641.jpg)

*Detail snímacích vodičov vložených do nádoby. Vodivé kontakty slúžia ako hladinové elektródy.*

![Umiestnenie pri vonkajšej jednotke klimatizácie](docs/IMG_20260624_113654.jpg)

*Širšia inštalácia pri vonkajšej jednotke klimatizácie, kde kondenz steká hadicou do zbernej nádoby.*

## Inštalácia

1. Zapoj snímače hladiny do nádoby. Priprav jednu spoločnú elektródu a štyri elektródy pre úrovne `level1..level4`. Pri ESP8266 pridaj pull-down rezistory z level vstupov na `GND`.
2. Skontroluj pin mapping v `arduino/arduino.ino`, hlavne `PIN_COMMON_ELECTRODE`, `PIN_LEVEL1`, `PIN_LEVEL2`, `PIN_LEVEL3` a `PIN_LEVEL4`.
3. Nastav WiFi v konštantách `WIFI_SSID` a `WIFI_PASS`. Pri zdieľaní projektu nepoužívaj reálne heslá v commitoch.
4. Nastav serverovú URL v konštante `URL_LOG`, napríklad na HTTPS adresu, kde je dostupný `server/log.php`.
5. Nahraj firmware cez Arduino IDE alebo `arduino-cli`.
6. Na server nahraj adresáre `server/` a vytvor alebo povoľ zápis do adresára `data/`.
7. Over syntax PHP skriptov:

```sh
php -l server/log.php
php -l server/data-checker.php
php -l server/functions.inc.php
```

8. Nastav CRON úlohu pre kontrolu výpadku monitorovania. Príklad hodinového spúšťania:

```cron
0 * * * * php /cesta/k/projektu/server/data-checker.php
```

9. Otestuj odoslanie merania na server:

```sh
curl -X POST https://example.com/hladinac/server/log.php \
  -d "level1=1&level2=1&level3=0&level4=0"
```

Server by mal vrátiť JSON odpoveď so `success: true` a do `data/YYYY.jsonl` by mal pribudnúť jeden riadok.

## Vývoj a ladenie

Arduino sketch podporuje tri režimy cez konštantu `DEBUG`:

- `DEBUG == 0`: produkčný režim, jedno meranie, odoslanie na server a deep sleep.
- `DEBUG == 1`: lokálne čítanie hladiny a výpis na sériovú linku bez WiFi.
- `DEBUG == 2`: opakované meranie a odosielanie na server každých 5 sekúnd.

Príklady príkazov:

```sh
arduino-cli compile --fqbn esp8266:esp8266:nodemcuv2 arduino
arduino-cli upload -p COM3 --fqbn esp8266:esp8266:nodemcuv2 arduino
arduino-cli monitor -p COM3 -c baudrate=115200
```

Pre ESP32 treba zmeniť `--fqbn` podľa použitej dosky, napríklad:

```sh
arduino-cli compile --fqbn esp32:esp32:esp32 arduino
```
