Przeróbka radiowej nakładki na licznik wody na DIY, na bazie ESP32-C3

Jestem Nowy na tym forum Pozdrawiam wszystkich
(mod-edit - przeniesiono ^ z tytułu wątku…)

Moi drodzy

zrobiłem sobie sam całe oprogramowanie do licznika wody Apator. wyrzuciłem z płytki STM i wlutowałem tam esp32-c3 super mini.
podłączyłem wszystkie trzy diody odbiorcze i środkową nadawczą. Firmware początkowo oparłem o odczyt z trzech diod odbiorczych, puki nie zauważyłem że diody odbiorcze bardzo dobrze reagują na światło słoneczne i gdy słońce wtargnie do piwnicy nagle progi które ustawiłem w programie są stanowczo przekroczone więc pisze obecnie automat który z jednej diody zrobi rzeczywisty pomiar natężenia światła, i tu mnie oświeciło może ja posiadam zły wodomierz bo cała góra zrobiona jest z przezroczystego tworzywa i choćbym się starał ogarnąć automaty i kalibrację w czasie rzeczywistym, wyłuskać z tego impulsy bęzie bardzo ciężko a zatem zapewnienie stałych odczytów również.. czy ktoś wie jak oni to zrobili że mają stabilne odczyty?

1 polubienie

Odpowiem również w jednym zdaniu - TAK :slightly_smiling_face:

Tak złożonego zdania pozazdrościłby nawet prof.Bralczyk.

3 polubienia

o wiem czepiasz się to sobie poczytaj MIASTENIA GRAVIS jedno oko u góry w lewo drugie na wprost i jeszcze to co w lewo jest skręcone w osi wprawo napisz tak cokolwiek na klawiaturze będziesz lepszy ode mnie

Miodek by powiedział, że “odpowiedzieć komuś” to forma poprawna, ale “odpowiedzieć komuś z sensem” to już wyższa szkoła jazdy. :joy:

Temat wątku też ciekawy…

Do jakiego modelu wodomierza? Apator ma najczęściej możliwość dołożenia fabrycznej nakładki radiowej. Taką nakładkę integruje się przez radiowy odbiornik i wmbusmeters.
wmbus wmbusmeters apator

1 polubienie

NAKŁADKA RADIOWA WODOMIERZA AT WMBUS-162 APATOR DEMONTAŻ • Cena, Opinie - Allegro

Wodomierz licznik do zimnej wody 3/4" APATOR • Opinie - Allegro

takie kupiłem

a to napisałem

nigdy nie doszło do tego by dane pokazały minimum ale to stary soft oparty na wszystkich trzech diodach IR
i raport
=== WODOMIERZ DIAGNOSTYKA ===
Czas: 2026-04-20 16:42:41
Uptime [ms]: 691854441

— LICZNIK —
total_liters: 79.8650 L
total_at_15: 79.8500 L
zuzycie_15_15: 0.0150 L

— KALIBRACJA —
liters_per_pulse: 0.001000 L
adc_threshold_A: 391
adc_threshold_B: 719
adc_threshold_C: 333
min_edge_us: 2000

— ADC BIEZACE —
A (GPIO0): 102
B (GPIO1): 1098
C (GPIO3): 8

— ADC MIN (od ostatniego resetu) —
A_min: 0
B_min: 0
C_min: 0

— ADC MAX (od ostatniego resetu) —
A_max: 783
B_max: 1532
C_max: 665

— ZALECANY PROG —
A_suggest: 391
B_suggest: 766
C_suggest: 332

— IMPULSY / ISR —
isr_cnt: 73274284
a_tog: 5335206
b_tog: 69186541
c_tog: 14918
reverse_cnt: 3100 (cofnięcia — ignorowane)
age_ms: 3 ms

— STAN SYSTEMU —
ir_enabled: TAK
rgb_enabled: NIE
config_mode: NIE
wifi_ok: TAK
wifi_ssid: Apple Network
wifi_ip: 10.100.21.233
report_pending: NIE

=== KONIEC RAPORTU ===

Tylko, aby miało wartośc dla kogoś, to przydałoby się coś więcej.

Wodomierz i nakładka zdają się pasować do siebie.

Nie miałem tej nakładki w ręku, ale uważam, że prawidłowo zainstalowana na wodomierzu nie powinna dopuszczać światła z zewnątrz do układu pomiarowego (mogę się mylić, oceniam tylko zdjęcia). Ewentualnie oprogramowanie w tym STM było na to przygotowane i potrafiło adoptować płynnie układ.


Za prawidłowe oświetlenie obrotowej tarczy odpowiada dodatkowa LED. Strasznie sobie to wszystko skomplikowałeś zamiast użyć fabrycznych rozwiązań. Jak wstawiłeś tam ESP, to domyślam się, że doszło jeszcze zasilanie zewnętrzne, bo raczej na baterii nie podziała to za długo. Musisz sam ocenić jakim sposobem dostaje się światło z zewnątrz i jak bardzo zmieniłeś układ wraz z jego logiką po stronie optycznej. Czy te LED są dobrze wysterowane… itd.
A wystarczyło kupić nakładkę z impulsatorem, jak już chciałeś bardzo użyć tego ESP lub wodomierz ze stalową tarczką i czujnik indukcyjny.

P.S. Jak ktoś jest chętny, to mam swoje DIY do sprzedania.

Tak wywalając z płytki procka usunąłem również baterię i całość jest zasilana z portu usb i logika pracuje na 3,3 a nie na 3,6 bo tyle dawała bateria różnica 0.3 V może mieć znaczenie ale przez moje oczy nawet przez mikroskop nie wymienię już rezystorów

Mimo, że ta nakładka jest z czarnego tworzywa, to na dedykowanym liczniku nie gwarantuje całkowitej izolacji optycznej od otoczenia.
Więc w sytuacji j/w. można zamontować skrzynkę wodomierzową (w praktyce widywałem tylko metalowe, co może być istotną przeszkodą dla WiFi) albo jakąś własną konstrukcję DIY.

I w zawiązku z tym wrócę do kluczowego pytania

Nie wiem jak zrobili, ale logika wskazuje na kompensację warunków w trakcie pomiaru, czyli każdy pomiar zapewne odbywa się dwufazowo z wysterowaniem LED IR ciemno/jasno (lub nawet trójfazowo ciemno/jasno/ciemno), gdzie bias jest wyznaczany z faz(y) bez oświetlenia.

BTW
Mam liczniki dostawcy właśnie z nakładkami Apator 16-2 (i albo nie zdążyłem zobaczyć jakie były liczniki, albo przy montażu były już dostarczone zmontowane z nakładkami), więc nie wiem czy nie są już w wersji z lusterkiem na 2/3 koła, ale odczyty radiowe są stabilne jak skała.

Natomiast zdemontowano mi wcześniejsze liczniki z tarczą na pół koła (z nakładkami Apator 8) i tamte miały tendencje do fluktuacji wskazań właśnie o 1/3 obrotu wskazówki ze sprzęgiem optycznym.

czyli postawiłem nie na tego konia… no cóż jeszcze się pomęczę albo okleję licznik czarną taśmą izolacyjną, wcześniej miałem kamerę która badała ruch robiła fotkę następnie forka była pobirana z kamery i programem ocr zaczytywany wynik

Świetny gotowy projekt tego rodzaju to ai-on-the-edge

Przerobiłem program, zrobiłem automatyczną kalibrację i narazie odczyt tylko jednej diody odbiorczej.

Okazało się że układ działa i liczy impulsy przy wyłączonej diodzie nadawczej tej białej po środku, co dało mi mocno do myslenia. do puki słońce docierało do licznika działał a w nocy nie więc obecnie przerobiłem program by automatycznie regulował jasność diody nadawczej na podstawie odczytu światła z diody odbiorczej i dam wam znać za dwa dni

Kolejny raz proszę (nalegam) aby zamieszczać, przydatne informacje w postaci np. kodu, schematu i fotek.
Dotychczas, jeśli ktoś chciałby sobie coś takiego powtórzyć albo pomóc - nie jest w stanie.
Pozostaje tylko wierzyć, że udało Ci się napisać jakiś program bez używania: wielkich/małych liter, kropek i przecinków i jednej linii.
Jeśli nic się nie zmieni to będziesz gadał sam ze sobą.

Czy masz może jakieś pytania i w czym konkretnie oczekujesz pomocy?

A nie powinien.

Może niejasno napisałem wyżej, ale z zasady prostota rozwiązania musi być maksymalna
ciemno=wyłączony LED IR, jasno=włączony
bias prawdopodobnie jest wyznaczany na każdej fotodiodzie (czy tam fototranzystorze) osobno.
Algorytmu nie znam, ale można założyć, że tam gdzie jest duża delta odczytu, to jest w danym momencie lusterko, jeśli jest mała delta, to czarny fragment tarczy.

proszę oto uproszczony kod z wszystkimi zależnościami i logiką

/*╔══════════════════════════════════════════════════════════════╗║  WODOMIERZ — ESP32-C3 Super Mini                            ║║  Apator JS2.5-GI-02                                         ║║  Czujnik B (GPIO1) — liczenie impulsów                      ║║  Czujniki A (GPIO0) + C (GPIO3) — ambient (dynamiczny próg) ║╚══════════════════════════════════════════════════════════════╝

Zasada działania:

Tarcza wodomierza podzielona na pół: czarna / lustrzana

Dioda IR nadawcza w centrum tarczy (GPIO10, aktywna LOW)

Trzy fotorezystory na szczytach trójkąta wpisanego w tarczę

Kanał B (GPIO1) liczy impulsy — zbocze opadające = 1 impuls

Kanały A (GPIO0) i C (GPIO3) mierzą światło otoczenia

Próg dynamiczny = (A + C) / 2 + offset

Dzięki temu zmieniające się oświetlenie (słońce przez okno)nie wpływa na wykrywanie impulsów

Kalibracja:

Nalej dokładnie 1L wody i sprawdź ile impulsów zliczył Serial

Wpisz: LITERS_PER_PULSE = 1.0 / liczba_impulsow*/

 <Arduino.h> <esp_timer.h>

// ════════════════════════════════════════════════════════════════//  PINY// ════════════════════════════════════════════════════════════════static const int PIN_PHOTO_A = 0;   // fotorezystor A — ambientstatic const int PIN_PHOTO_B = 1;   // fotorezystor B — tarcza (główny)static const int PIN_PHOTO_C = 3;   // fotorezystor C — ambientstatic const int PIN_IR_LED  = 10;  // dioda IR nadawcza (ON = LOW)

// ════════════════════════════════════════════════════════════════//  KALIBRACJA// ════════════════════════════════════════════════════════════════static const float    LITERS_PER_PULSE     = 0.001f;  // L/impuls — ustaw empiryczniestatic const int      DYNAMIC_OFFSET       = 200;     // próg = ambient + offsetstatic const uint32_t MIN_PULSE_INTERVAL_US = 5000;   // anty-drgania [µs]

// ════════════════════════════════════════════════════════════════//  ZMIENNE// ════════════════════════════════════════════════════════════════static volatile int      adc_a = 0, adc_b = 0, adc_c = 0;static volatile int      dynamic_threshold = 500;static volatile uint32_t pulse_total    = 0;static volatile uint32_t last_pulse_us  = 0;static volatile uint8_t  b_state_prev   = 0;static float             total_liters   = 0.0f;

static esp_timer_handle_t adc_timer_handle = NULL;

// ════════════════════════════════════════════════════════════════//  TIMER ADC — odpytuje czujniki co 5ms (200 Hz)// ════════════════════════════════════════════════════════════════static void IRAM_ATTR adc_poll_cb(void* arg) {int va = analogRead(PIN_PHOTO_A);int vb = analogRead(PIN_PHOTO_B);int vc = analogRead(PIN_PHOTO_C);

adc_a = va; adc_b = vb; adc_c = vc;

// Dynamiczny próg — kompensacja światła otoczeniaint ambient = (va + vc) / 2;dynamic_threshold = ambient + DYNAMIC_OFFSET;

// Zbocze opadające na B = impuls (tarcza przeszła lustro → czarny)uint8_t b_cur  = (vb >= dynamic_threshold) ? 1 : 0;uint8_t b_prev = b_state_prev;b_state_prev = b_cur;

if (b_prev == 1 && b_cur == 0) {uint32_t now_us = (uint32_t)esp_timer_get_time();if ((now_us - last_pulse_us) >= MIN_PULSE_INTERVAL_US) {last_pulse_us = now_us;pulse_total++;}}}

// ════════════════════════════════════════════════════════════════//  SETUP// ════════════════════════════════════════════════════════════════void setup() {Serial.begin(115200);delay(200);

// Dioda IR nadawcza — włączpinMode(PIN_IR_LED, OUTPUT);digitalWrite(PIN_IR_LED, LOW);  // ON = LOW

// Wejścia ADCanalogReadResolution(12);pinMode(PIN_PHOTO_A, INPUT);pinMode(PIN_PHOTO_B, INPUT);pinMode(PIN_PHOTO_C, INPUT);

// Timer ADC co 5msesp_timer_create_args_t args = {};args.callback = adc_poll_cb;args.name     = “adc_poll”;esp_timer_create(&args, &adc_timer_handle);esp_timer_start_periodic(adc_timer_handle, 5000); // 5000µs = 5ms

Serial.println(“=== WODOMIERZ START ===”);Serial.printf(“L/impuls: %.6f | offset: %d\n”, LITERS_PER_PULSE, DYNAMIC_OFFSET);}

// ════════════════════════════════════════════════════════════════//  LOOP// ════════════════════════════════════════════════════════════════static uint32_t last_pulse_reported = 0;static uint32_t last_print_ms       = 0;

void loop() {// Sprawdź czy przybyły nowe impulsyuint32_t current_total = pulse_total; // odczyt volatileif (current_total != last_pulse_reported) {uint32_t new_pulses = current_total - last_pulse_reported;last_pulse_reported = current_total;total_liters += (float)new_pulses * LITERS_PER_PULSE;

Serial.printf("Impuls! total_impulsow=%lu | %.3f L | ADC: A=%d B=%d C=%d | prog=%d\n",
              current_total, total_liters,
              (int)adc_a, (int)adc_b, (int)adc_c,
              (int)dynamic_threshold);

}

// Co 2 sekundy wypisz stan nawet bez impulsuif (millis() - last_print_ms > 2000) {last_print_ms = millis();Serial.printf(“Stan: %.3f L | impulsy=%lu | A=%d B=%d C=%d | prog=%d\n”,total_liters, current_total,(int)adc_a, (int)adc_b, (int)adc_c,(int)dynamic_threshold);}

delay(10);}

________________________________________________________

Poprzedni kod (3 czujniki, kod Graya):

Wszystkie 3 kanały (A, B, C) montowane na tarczy.
Kierunek obrotu wykrywany przez tabelę Graya 3-bitową.
Stały próg ADC ustawiany ręcznie przez WWW.

Problem: zmieniające się oświetlenie (słońce) zawyżało progi i blokował zliczanie.

Nowy kod (1 czujnik + ambient):

Kanał B — jedyny liczący impulsy (zbocze opadające lustro→czarny).
Kanały A i C — mierzą tylko światło otoczenia a raczej starają się to robić.
Próg dynamiczny = (A + C) / 2 + offset — automatycznie podąża za zmianami oświetlenia.
Brak kodu Graya — prościej, i tak myślę że mniej podatne na błędy.
Brak detekcji kierunku.
Auto-kalibracja przez WWW — program sam wyznacza offset obserwując MIN/MAX kanału B gdy leci woda.

Dlaczego tak:
Okazało się że kanały A i C praktycznie nie reagowały na tarczę (a_tog=5M, c_tog=15k vs b_tog=85M w logach diagnostycznych) — tylko B był użyteczny. Zamiast marnować A i C na słaby odczyt tarczy, lepiej użyć ich do kompensacji światła otoczenia.
Poza tym ponieważ od samego początku zawsze kanał B wykazywał większą aktywność, tak myślę jeszcze tego nie potwierdziłem może to nie są trzy identyczne elementy optyczne?
i ta jedna jest lekko oddalona od środka układu czyli diody nadawczej białej.

To są 3 identyczne elementy (przy projektowaniu nikt sobie nie strzela w stopę utrudniając życie to jedno, a drugie, że produkcyjnie jest taniej wykonać coś z 3 jednakowymi elementami, co ma kluczowe znaczenie jeśli produkcja jest wielkoseryjna).
Na 100% nie są to fotorezystory (fotodiody lub bardziej prawdopodobne fototranzystory).
Jeśli masz drastycznie różne zachowanie każdego sensora trzeba dokładnie skontrolować układ pod kątem zwarć, przerw i ogólnej poprawności połączeń.
Może skutkiem modyfikacji jest niewłaściwy montaż mechaniczny nakładki (fabrycznie zespół sprzęgu optycznego musi być możliwie blisko tarczy, dlatego obudowa jest dość specyficznie projektowana zarówno licznika jak i nakładki).

Spromptuj to AI pod kątem odczytu w sposób jaki sugerowałem (sprawdzenie stanu czujników bez oświetlenia i z oświetleniem), algorytm może być znacznie bardziej skomplikowany, bo do detekcji w ten sposób trzeba przechowywać oba stany każdego czujnika (oświetlonego i nieoświetlonego), być może też jakąś wartość uśrednioną jakimś sensownym filtrem - może mediana się sprawdzi, bo de facto trzeba wykryć 3 stany lusterka - Jest lusterko, nie ma lusterka, jest stan przejściowy/krawędź (stawiam, na to że AI to wymyśli sensownie), 3 czujniki są potrzebne z kilku względów, między innymi wykrywania ruchu wstecznego, ale też umożliwiają bardziej niezawodne zliczanie.

Jeśli masz problem z “lewym” światłem upewnij się, że twój MCU nie świeci jakimiś LEDami w środku (fototranzystory są wprawdzie w czarnych obudowach by zmniejszyć ich czułość poza zakresem IR, ale zwykle nie da się uzyskać całkowitego braku reakcji na zakres widzialny szczególnie w okolicach czerwieni), ewentualnie chociaż tymczasowo zamknij to w szczelnym kartonowym pudełku, bezpośrednie światło słoneczne ma niewyobrażalnie dużą moc w porównaniu do tej lokalnej diodki LED IR.

200 pomiarów na sekundę nie ma racji bytu (ile faktycznie potrzeba da się wyznaczyć z maksymalnego przepływu tego licznika, ale gwarantuję, że fabrycznie to ta nakładka nie mierzy tak często, bo bateria nie starczyłaby na 10 lat pracy niezależnie od tego jak bardzo energooszczędny jest fabryczny MCU, choć sam pomiar może trwać istotnie bardzo krótko, ale do tego trzeba znać chociaż szacunkowe parametry użytych elementów).

BTW tu masz przykład datasheetu podobnego fototranzystora (warto czytać do końca)