Dokumentacja stacji pomiarowej MFC
Kompletny opis sprzętu, parametrów konfiguracji, znaczenia każdej karty KPI, wykresu i kolumny w tabeli odczytów. Strona statyczna — zawsze odpowiada bieżącej wersji frontendu i backendu.
1. Przegląd systemu
Stacja Pomiarowa MFC to system telemetryczny do monitorowania kontrolera przepływu masowego (Mass Flow Controller) wraz z parametrami elektrycznymi obwodu zasilającego. Składa się z trzech warstw:
- ESP32 — odczytuje czujniki, buforuje dane, wysyła JSON-em po HTTPS POST na backend co kilka sekund.
- Backend Node.js (Express + better-sqlite3, port 3002, za nginx-em) — odbiera dane, retransmituje do przeglądarki przez WebSocket, decyduje kiedy zapisać do bazy SQLite.
- Dashboard (Vite/vanilla JS + Chart.js) — wyświetla aktualne wartości w czasie rzeczywistym oraz historię z bazy.
monitor-mfc.roleplayingtech.com (HTTPS, certyfikat Let's Encrypt). Nginx serwuje statyki z /var/www/monitor-mfc.roleplayingtech.com/frontend/dist i proxy-uje /api oraz /ws na 127.0.0.1:3002.
2. Układ pomiarowy
Cztery komponenty fizyczne i jeden gaz źródłowy:
| Element | Funkcja | Adres / interfejs |
|---|---|---|
| MFC (Mass Flow Controller) | Mierzony obiekt. Wystawia analogowe napięcie 0–5 V proporcjonalne do aktualnego przepływu w sccm. | Wyjście analogowe (Vout) → MCP6002 |
| MCP6002 (op-amp) | Bufor wysokoimpedancyjny, dwie połowy. Izoluje wyjście MFC od wejścia ADC i zapewnia niską impedancję dla próbkowania. | Lewa połowa (piny 1,2,3) → ADS1115 AIN0 · Prawa połowa (5,6,7) → AIN1 |
| ADS1115 | 16-bitowy ADC, I²C, 4 kanały single-ended. Konfigurowalny wzmacniacz programowy (PGA) i częstotliwość próbkowania. | I²C, adres 0x48, SDA=GPIO21, SCL=GPIO22 |
| INA219 | Czujnik prądu/napięcia/mocy szyny zasilającej. Mierzy spadek na shuncie i napięcie magistrali — wylicza prąd i moc. | I²C, adres 0x40 |
| ESP32 | Mikrokontroler. WiFi, NTP, składa JSON-a, wysyła do backendu po HTTPS. | Master I²C, klient HTTPS, klient NTP |
Po co MCP6002? Wyjście MFC ma stosunkowo wysoką impedancję — bezpośrednie podłączenie do ADC powoduje obciążenie sygnału i zafałszowanie pomiaru. Op-amp w konfiguracji wtórnika napięciowego (gain = 1) podaje na ADC napięcie identyczne, ale ze źródła niskoimpedancyjnego.
Po co osobny ADC zamiast tego w ESP32? ADC w ESP32 jest 12-bitowy, mocno nieliniowy i hałaśliwy. ADS1115 to 16-bit, kalibrowany fabrycznie, ze stabilnym referencyjnym napięciem i konfigurowalnym PGA — krytyczne dla pomiarów analogowych z MFC.
3. Połączenia / pinout
| Linia | Skąd | Dokąd | Uwagi |
|---|---|---|---|
| Vout MFC #1 | MFC #1 | MCP6002 IN+ (lewa połowa, pin 3) | 0–5 V, sygnał liniowy względem przepływu |
| Bufor V1 | MCP6002 OUT (pin 1) | ADS1115 AIN0 (Ch0) | Buforowane napięcie 1 — używane do wyliczenia flow_value |
| Bufor V2 | MCP6002 OUT (pin 7) | ADS1115 AIN1 (Ch1) | Drugie napięcie — opcjonalne, włączane przez tryb dual voltage |
| AIN2, AIN3 | — | — | Wolne kanały, do dodatkowych pomiarów (np. napięcie ogniwa). Odczytywane zawsze, zapisywane do bazy. |
| I²C | ESP32 GPIO21 (SDA), GPIO22 (SCL) | ADS1115 + INA219 | Standardowy bus, oba urządzenia adresowane unikalnie |
| Shunt INA219 | Vbus + | Obciążenie | Spadek napięcia → prąd; suma → load voltage |
| Zasilanie | 5 V / 3.3 V | Sensory + ESP32 | Zasilanie oddzielne dla ESP i MFC zalecane |
4. Przepływ danych
MFC → MCP6002 → ADS1115 ┐
├──► ESP32 ──► HTTPS POST ──► Backend (Node.js)
INA219 ─────┘ │
├──► SQLite (zrzut wg interwału / change)
└──► WebSocket ──► Dashboard
Trzy niezależne częstotliwości:
- ESP send interval — jak często ESP32 wysyła JSON-a (domyślnie 2000 ms; rzeczywista ~10 s w testach). Każda wysyłka trafia po WebSocket-cie do dashboardu i odświeża KPI/wykresy/konsolę.
- DB save interval — jak często backend trwale zapisuje pomiar do SQLite (domyślnie 5 min). Większość wysyłek z ESP nie jest zapisywana, są tylko pokazywane na żywo.
- Change-triggered save — jeżeli włączone, backend dodatkowo zapisuje pomiar gdy Przepływ / Ch0 / Ch1 wykona skok większy niż próg (patrz sekcja 11).
5. Karty KPI
Sześć kart na górze dashboardu, aktualizowane na każdy nowy pomiar z WebSocketa:
| Karta | Wartość główna | Pole pod spodem |
|---|---|---|
| Przepływ | flow_rate.value w sccm | Procent zakresu MFC + pasek postępu |
| Napięcie (Bus) | INA219 bus_voltage [V] | Load V (Bus + Shunt) i Shunt mV |
| Prąd | INA219 current_mA | Aktywna kalibracja INA219 |
| Moc | INA219 power_mW | Skumulowana energia w mWh (od startu backendu) |
| WiFi / ESP32 | RSSI w dBm | Heap / min Heap, temperatura chipu, wartość Hall sensor |
| ADS1115 | 4 napięcia kanałów (Ch0–Ch3) | PGA gain · data rate · rozdzielczość |
6. Wykresy
| Wykres | Co pokazuje | Skala |
|---|---|---|
| Przepływ w czasie rzeczywistym | sccm w funkcji czasu | 1 / 5 / 15 / 60 min — przyciski u góry |
| Napięcia ADS1115 (4 kanały) | 4 linie napięć z AIN0–AIN3 | Volt |
| Napięcia INA219 | Bus, Load, Shunt jednocześnie | Volt + mV (osobne osie) |
| Prąd i Moc (INA219) | Dwie krzywe, podwójna oś Y | mA i mW |
| Energia skumulowana | Narastające mWh | mWh |
| Diagnostyka ESP32 | RSSI + heap + temperatura chipu | Wiele osi |
Wszystkie wykresy są live — buforowane w pamięci przeglądarki, okno czasowe stałe. Po reloadzie strony bufor się czyści; historia z bazy danych jest oddzielnie w tabeli "Ostatnie odczyty".
7. Tabela "Ostatnie odczyty" — każda kolumna
Tabela pokazuje ostatnie zapisy z bazy danych (nie z live-streamu). Sortowanie po dowolnej kolumnie (klik w nagłówek), paginacja po 20 wierszy. Wiersze z bursztynowym tłem i ⚡ to change-triggered saves.
| Kolumna | Pole DB | Znaczenie |
|---|---|---|
| Czas | timestamp | Czas zdarzenia z ESP32. Jeżeli ESP nie zsynchronizował NTP, jest to liczba milisekund od bootu — wtedy wartości w 1970 r. są oczekiwane. Server-side created_at to faktyczny moment zapisu w SQLite. |
| Przepływ | flow_value + flow_percentage | Liczbowo w sccm i w nawiasie procent zakresu MFC. Liczone z napięcia AIN0 i kalibracji mfc_voltage_min/max + mfc_flow_max. |
| Ch0 (V1) | ads_ch0_voltage | Napięcie z AIN0 — zwykle buforowany sygnał MFC #1. |
| Ch1 (V2) | ads_ch1_voltage | Napięcie z AIN1 — drugi sygnał (np. drugi MFC, drugie ogniwo). Aktywny wizualnie gdy włączony tryb dual voltage. |
| Ch2 / Ch3 | ads_ch2_voltage / ads_ch3_voltage | Wolne kanały AIN2/AIN3 — odczytywane i zapisywane zawsze. Można podpinać dodatkowe pomiary bez zmian w kodzie. |
| Bus V | bus_voltage | Napięcie magistrali zasilającej obciążenie (mierzone przez INA219, względem GND). |
| Load V | load_voltage | Napięcie na samym obciążeniu = Bus + Shunt. |
| Shunt mV | shunt_voltage_mV | Spadek napięcia na rezystorze shunt — z niego liczony jest prąd. |
| Prąd | current_mA | Prąd przez obciążenie, mA. |
| Moc | power_mW | Moc chwilowa = Bus × Current. |
| Energia | energy_mWh | Energia skumulowana od ostatniego startu backendu. Reset przy pm2 restart. |
| RSSI | wifi_rssi | Siła sygnału WiFi w dBm widzianego przez ESP. Im bliżej 0, tym lepiej (-50 = świetnie, -90 = na granicy). |
| Heap | free_heap | Wolny heap ESP32. Spadek w czasie = możliwy memory leak. |
| Temp | chip_temp | Temperatura chipu ESP32 (z wbudowanego sensora — odczyt orientacyjny). |
| Hall | hall_sensor | Czujnik Halla wbudowany w ESP32. W ESP-IDF 5.x usunięty — pole zwykle 0/null. |
8. Statystyki sesji
Panel "Statystyki sesji" pokazuje min / max / avg liczone tylko z odczytów odebranych w bieżącej sesji przeglądarki (nie z całej historii w bazie). Reload strony → liczniki od zera. Liczone w locie z każdego przychodzącego pomiaru WebSocket-em.
9. Konsola live
Strumień diagnostyczny każdego odebranego pomiaru. Dwa typy linii:
- 📡 Live data — pomiar z ESP, jeszcze niezapisany do bazy.
- 💾 Saved — backend zapisał ten pomiar do SQLite (potwierdzenie z polem
id).
Kontrolki: Autoscroll (auto-przewijanie do nowych linii), Pauza (zatrzymuje dopisywanie bez przerywania połączenia), Wyczyść.
10. Konfiguracja — wszystkie pola
Cała konfiguracja jest globalna (zapisywana w SQLite po stronie backendu, w tabeli config). Każda zmiana zatwierdzona przyciskiem "Zapisz konfigurację" rozsyłana jest WebSocket-em do wszystkich otwartych dashboardów. Lista pól:
| Pole UI | Klucz konfigu | Opis |
|---|---|---|
| Komentarz do pomiaru | measurement_comment | Wolny tekst — jeśli niepusty, pojawia się jako baner u góry dashboardu. Na potrzeby opisania bieżącej kampanii pomiarowej. |
| Tryb pomiaru napięcia | dual_voltage_mode | false = tylko Ch0 (jedno napięcie z MCP6002). true = dodatkowo Ch1. Wpływa wyłącznie na to co pokazujemy/podpisujemy w UI — firmware zawsze odczytuje wszystkie 4 kanały ADS. |
| Etykieta kanału A0 / A1 | channel_0_label / channel_1_label | Tekst używany na karcie KPI ADS1115 (skraca do 20 znaków + ":"). |
| Komentarz Ch0 / Ch1 | channel_0_comment / channel_1_comment | Notatka opisowa dla kanału — tylko zapisywana, nie renderowana w głównych widokach. |
| Interwał zapisu do bazy | save_interval_minutes | Co ile minut backend trwale zapisuje pomiar. Dotyczy "regularnych" zapisów (oznaczonych change_triggered=0). Zakres 0.5–1440. |
| Interwał wysyłania ESP | esp_send_interval_ms | Co ile milisekund ESP wysyła pomiar. Backend zwraca tę wartość w odpowiedzi POST, ESP może ją honorować. Zakres 500–60000. |
| Kalibracja MFC | mfc_voltage_min / mfc_voltage_max / mfc_flow_max | Zakres napięcia odpowiadający 0% / 100% przepływu i maksymalny przepływ w sccm. Używane do mapowania ads_ch0_voltage → flow_value. |
| Kalibracja INA219 | ina219_calibration | Tryb pracy INA219. 32V_2A największy zakres, 32V_1A standardowy, 16V_400mA najwyższa rozdzielczość. Wymaga ponownego wgrania firmware aby zmienić. |
| PGA ADS1115 | ads1115_gain | Wzmocnienie programowalne ADS1115. Wyższe = mniejszy zakres napięcia ale lepsza rozdzielczość. Wymaga ponownego wgrania firmware. |
| Zapis przy nagłej zmianie | change_detection_enabled | true/false. Włącza dodatkowe zapisy poza regularnym interwałem. |
| Progi zmiany | change_threshold_flow / _ch0 / _ch1 | Minimalna różnica vs. ostatnio zapisany pomiar która kwalifikuje zapis. sccm dla flow, V dla Ch0/Ch1. Uwaga: progi 0.01 V są poniżej szumu ADC — sprzyjają spamowaniu bazy. |
| Widoczność kolumn | table_visible_columns | CSV widocznych kolumn tabeli. Pusty = wszystkie. Zmieniany z dropdownu "Kolumny" nad tabelą, synchronizowany globalnie. |
11. Zapis przy nagłej zmianie
Standardowo backend zapisuje do bazy raz na save_interval_minutes (np. co 5 min) — większość pomiarów leci tylko przez WebSocket i znika. Ten mechanizm dodatkowo zapisuje pomiar zaraz poza regularnym oknem, jeżeli któryś z trzech kluczowych sygnałów wykonał skok > próg względem ostatnio zapisanego pomiaru:
- Przepływ (sccm) — próg
change_threshold_flow - Ch0 / V1 (V) — próg
change_threshold_ch0 - Ch1 / V2 (V) — próg
change_threshold_ch1
Takie wpisy mają w bazie change_triggered=1 i w tabeli pojawiają się z bursztynowym tłem oraz ikoną ⚡. Regularne zapisy mają change_triggered=0.
save_interval_minutes.
Strojenie progów: dla ADS1115 z PGA ±4.096V szum jest rzędu 1–3 mV. Próg 0.05 V łapie wyraźne skoki bez fałszowania szumem. Próg 0.01 V łapie też szum — sensowne tylko jeżeli sygnał jest bardzo stabilny i naprawdę chcesz każdy mikro-skok.
12. Widoczność kolumn
Przycisk "Kolumny" nad tabelą otwiera listę 16 dostępnych kolumn — odznaczone są ukrywane. Stan zapisywany jest globalnie (klucz table_visible_columns w tabeli config) — każda zakładka i każdy użytkownik widzi tę samą listę. Przyciski "Wszystkie" i "Żadna" w nagłówku menu szybko resetują stan.
13. Co jest zapisywane globalnie, a co lokalnie
| Element | Gdzie | Trwałość |
|---|---|---|
| Konfiguracja (wszystkie pola panelu Konfiguracja) | SQLite, tabela config | Globalnie, trwale |
| Pomiary zapisane (regular + change-triggered) | SQLite, tabela readings | Globalnie, trwale |
| Widoczność kolumn tabeli | SQLite, klucz table_visible_columns | Globalnie, trwale |
| Statystyki sesji (min/max/avg) | Pamięć przeglądarki | Do reloadu strony |
| Bufor wykresów (live) | Pamięć przeglądarki | Do reloadu strony |
| Konsola live | Pamięć przeglądarki (max 200 linii) | Do reloadu strony / przycisku "Wyczyść" |
14. Endpointy API
| Metoda + URL | Opis |
|---|---|
POST /api/readings | ESP32 wysyła pojedynczy pomiar (JSON). Zwraca {status, saved, timestamp, next_interval_ms}. |
POST /api/readings/batch | Tablica pomiarów do hurtowego wstawienia. |
GET /api/readings?limit=&offset=&sortBy=&desc= | Paginowana lista zapisanych pomiarów. Sortowanie po większości kolumn. |
GET /api/readings/latest | Ostatni zapisany pomiar. |
GET /api/readings/range?from=&to= | Pomiary w przedziale timestampów (ms). |
GET /api/readings/stats | min/max/avg ze wszystkich (lub z zakresu) zapisanych pomiarów. |
GET /api/devices | Lista znanych urządzeń (z first/last_seen). |
GET /api/config · PUT /api/config | Pełny config / aktualizacja częściowa (filtruje do whitelisty kluczy). |
WS /ws | WebSocket. Eventy: connected (welcome + config), new_reading, reading_saved, config_update. |
15. FAQ / typowe problemy
- Tabela pokazuje datę 1970 — co się dzieje?
- ESP32 nie zsynchronizował NTP w momencie wysyłki — wysłał
millis()jako timestamp. Gdy NTP "złapie", kolejne pomiary mają normalną datę. Zapis wpadł do bazy normalnie (server-sidecreated_atjest poprawny). - Wszystkie ostatnie wpisy mają
change_triggered=1, brakuje regularnych zapisów. - Progi zmiany ustawione zbyt nisko — szum przekracza próg na każdym pomiarze. Podnieś
change_threshold_*(np. 0.05 V) lub wyłącz mechanizm. Regularny zapis i tak leci niezależnie cosave_interval_minutes. - Dashboard pokazuje "Łączenie...", brak danych live.
- WebSocket nie połączony — sprawdź czy backend działa (
pm2 status mfc-backend) i czy nginx proxy-uje/wsz nagłówkami Upgrade/Connection. - ESP wysyła ale backend loguje "Bad escaped character in JSON".
- Któryś klient (nie ESP) wysyła zniekształcony JSON. Może to być ślad starego procesu lub ręcznego curl-a — niegroźne dla normalnej pracy ESP.
- Po restarcie backendu energia pokazuje 0 mWh.
- Energia liczona jest w pamięci od startu procesu. Po
pm2 restartlicznik startuje od zera. Historia pomiarów w bazie pozostaje nienaruszona. - Chcę dodać czwarty pomiar napięcia (np. drugie ogniwo).
- Podepnij sygnał (najlepiej przez bufor MCP6002) do AIN2 lub AIN3. Firmware już odczytuje wszystkie 4 kanały, backend już zapisuje
ads_ch2_voltage/ads_ch3_voltage, frontend już je pokazuje w tabeli i na wykresie napięć ADS. Etykiety dla Ch2/Ch3 trzeba by jeszcze dodać do configu — to ~5 linii.