Skip to content
cukierrroPublic

About

Strażnik — nieoficjalne wczesne ostrzeganie o zagrożeniach powietrznych dla Polski. Fuzja sygnałów NEPTUN, mediów, RCB, ADS-B i PAŻP + aplikacja Android.

Topics

Resources

Contributing

Security policy

Stars

41 stars

Watchers

2 watching

Forks

Repository files navigation

Strażnik

Strażnik

Serwer: hostowane na Mikrusie — dziękujemy za wsparcie projektu.

Wersja 1.7.93: czerwony alarm dociera na zegarek z Wear OS, wibracja mówi alfabetem Morse'a (żółty „U”, czerwony „A”), a czerwony ma trzy tryby: syrena, sama wibracja albo zwykłe powiadomienie. Karta województwa mówi, do kiedy trzyma się poziom, a historia pokazuje to samo co mapa na żywo. Szczegóły: docs/RELEASE_1.7.93.md.

Wersja 1.7.92: poprawka bezpieczeństwa. Silnik aplikacji (Capacitor) podniesiony do wersji z poprawką publicznie ogłoszonej luki, a linki ze źródeł zewnętrznych nie mogą już prowadzić do wnętrza aplikacji. Wygląd i działanie bez zmian. Zalecamy aktualizację. Szczegóły: docs/RELEASE_1.7.92.md.

Wersja 1.7.91: podkarpackie słyszy drony, telefon ostrzega o uśpieniu. Obiekt punktuje teraz każde województwo w zasięgu, z wagą zależną od odległości do niego — dotąd punkty dostawało tylko województwo z najbliższym odcinkiem granicy, przez co drony lecące na podkarpackie liczyły się lubelskiemu (przeliczone na dwóch miesiącach historii: podkarpackie 17 → 27 żółtych sygnałów, lubelskie bez zmian, czerwonych nie przybywa). Aplikacja ostrzega, gdy telefon ogranicza jej baterię na nakładkach, które potrafią przez to wstrzymać powiadomienia, i pokazuje godzinę ostatniego sygnału z serwera. Strefy PAŻP znikają w podglądzie historii, bo nie zapisujemy ich w migawkach. Karta drona nie twierdzi już, że przyjmujemy „wariant groźniejszy” — odrzutowego Shaheda rozpoznajemy tylko z oznaczenia w źródle. Progi alarmów bez zmian. Szczegóły: docs/RELEASE_1.7.91.md.

Wersja 1.7.90: wielkość tekstu, świeży wykaz schronień i jedna prędkość w całej aplikacji. W Ustawieniach → Aplikacja doszedł wybór wielkości tekstu (Normalna / Większa / Największa) — powiększa wszystkie napisy naraz, działa od razu i mnoży się z systemowym rozmiarem czcionki na Androidzie. GROTA dostała wykaz PSP z 28 września (86 533 miejsca) oraz listę schronień do przejścia czytnikiem ekranu i klawiaturą. Czas dolotu liczy się teraz jedną regułą na serwerze i w aplikacji: prędkość typowa jest podłogą, a pomiar z ruchu może ją tylko podnieść — karta pokazuje dokładnie tę liczbę, na której oparty jest alarm. Naprawione: rozwinięty pasek źródeł wchodził pod pasek tytułu, a dron rozpoznawczy nie dostawał czasu dolotu. Punktacja i progi alarmów bez zmian. Szczegóły: docs/RELEASE_1.7.90.md.

Wersja 1.7.89: porządek w oknach. Ustawienia, legenda i okno „O aplikacji" nie wysypują już całej treści naraz — wyjaśnienia są schowane pod nazwanymi sekcjami przy swojej opcji, a sterowania zostają widoczne zawsze. Legenda dostała wreszcie przycisk zamykania, jej sześć grup rozwija się pojedynczo, a samolot i śmigłowiec rysowane są tą samą kreską co na mapie. Cały interfejs ma jeden kształt przycisku, a zdublowany „Zamknij" zniknął z pięciu okien. Przy okazji naprawione tłumaczenia: legenda i część ustawień zostawały po polsku w wersji angielskiej i ukraińskiej. Punktacja, progi i alarmy bez zmian. Szczegóły: docs/RELEASE_1.7.89.md.

Wersja 1.7.88: Strażnik czyta media także w Mołdawii, Rumunii, na Słowacji, w Czechach, Szwecji i na Węgrzech. Te sześć krajów podświetla się na mapie i ma własną kartę, ale nie dodaje ani jednego punktu — czeskie i słowackie redakcje piszą o cudzej przestrzeni powietrznej częściej niż o własnej, więc przez kilka tygodni tylko sprawdzamy, czy filtr nie bierze zdarzenia w Danii za ich własne. Przy okazji: karta kraju sąsiedniego nie otwierała się ani razu od 22 września, alarmy w rejonach Ukrainy są wreszcie tłumaczone, a na mapie przybyła Szwecja. Kamery w regionie to teraz sama lista z odnośnikami — podglądu nie pokazujemy, bo regulamin worldcam.pl na to nie zezwala. Szczegóły: docs/RELEASE_1.7.88.md.

Wersja 1.7.86: czerwony alarm może budzić samą wibracją. Nowy przełącznik ⚙ → Dźwięk → „Czerwony alarm: tylko wibracja, bez syreny” (Android) wycisza samą syrenę — wibracja, pełny ekran, miganie i przejście przez tryb Nie przeszkadzać zostają, a sparowany zegarek zawibruje tak samo. Ustawienia dźwięku przestały ze sobą walczyć: „Test: syrena” gra mimo ciszy, a opcja pełnej głośności jest przy niej nieczynna. Na iPhonie działa już przycisk zgody na alarm mimo wyciszenia — Apple przyznało uprawnienie Critical Alerts 28.09.2026, a przycisk z 1.7.84 chował się sam przed sobą. Szczegóły: docs/RELEASE_1.7.86.md.

Wersja 1.7.85: zakładka Zasady w GROCIE mówi to, co Komenda Główna PSP odpowiedziała na wniosek o informację publiczną (pismo z 25.09.2026). Wycofana obietnica dodania daty weryfikacji punktu — rejestr jej nie prowadzi i nie planuje udostępniać. Dopisane: co naprawdę znaczy „Dostępność”, czego urząd nie wyjaśnił (kto otwiera punkt „na żądanie” w czasie alarmu), że rejestr obejmuje też obiekty w postępowaniu i byłe budowle ochronne „bez wskazywania ostatecznej kategorii obiektów”, oraz że wykaz aktualizuje się raz w tygodniu i nie ma API. Działanie aplikacji bez zmian. Szczegóły: docs/RELEASE_1.7.85.md.

Wersja 1.7.84: widać, po której stronie granicy jest obiekt. Koło niepewności nie zaciemnia już mapy — zostaje sam przerywany okrąg, bo przyciemniona plama ±4 km kładła się na polskich wsiach i wyglądała jak zagrożenie nad nimi. Obiekt bliżej niż 10 km od granicy ma pod ikoną napisaną odległość: ikona ma 30 pikseli, więc sam rysunek tego nie rozstrzyga, a liczba tak. Na iPhonie doszedł przycisk zgody na alarm mimo wyciszenia (Apple przyznało uprawnienie 28.09; dotyczy wyłącznie czerwonego alarmu). Szczegóły: docs/RELEASE_1.7.84.md.

Wersja 1.7.83: mapa rysuje obiekt tam, gdzie go zgłoszono. Znacznik jechał zmierzonym kursem nawet 18 km przed ostatni meldunek, więc dron 0,2 km za granicą pod Dorohuskiem wyglądał na mapie, jakby był 3 km nad Polską — przy karcie, która w tym samym czasie pisała „0,2 km od granicy”. Przewidywanie pozycji usunięte; płynny przejazd między prawdziwymi meldunkami zostaje. Punktacja, progi i alarmy bez zmian — zawsze liczyły się ze zgłoszenia. Szczegóły: docs/RELEASE_1.7.83.md.

Wersja 1.7.82: mniej danych. Ilustracje obiektów przeszły z PNG na WebP — osiem plików waży 91 KB zamiast 12,4 MB, wyglądają tak samo, a APK chudnie o 12 MB. Mapa Ukrainy (pół megabajta) pobiera się dopiero, gdy są tam alarmy, zamiast przy każdym otwarciu. Serwer przysyła tylko tę część stanu, która się zmieniła, a przy pełnej ciszy w kraju telefon pyta co 15 zamiast co 5 sekund — gdy cokolwiek jest podniesione, tempo zostaje bez zmian. Zdjęcie maszyny w zwiniętej karcie jest większe. Punktacja i alarmowanie bez zmian. Szczegóły: docs/RELEASE_1.7.82.md.

Wersja 1.7.81: alarm da się odczytać czytnikiem ekranu. Ekran alarmu jest oknem alertdialog — czytnik przerywa to, co czyta, i podaje poziom oraz województwo, a tabulator krąży po jego przyciskach zamiast schodzić na zasłoniętą mapę. Wzrost poziomu do żółtego i powrót do zwykłego czytnik ogłasza sam, z nazwą województwa. Systemowe „ogranicz ruch” wyłącza wszystkie pulsujące elementy. Przy okazji okno aktualizacji nie wchodzi już pod górny pasek, a wiersz źródeł na mapie przewija się palcem. To pierwszy krok w stronę dostępności, a nie ogłoszenie, że aplikacja jest dostępna. Szczegóły: docs/RELEASE_1.7.81.md.

Wersja 1.7.80: alert RCB wysłany do kilku województw naraz przepadał bez śladu — listę odbiorców rozpoznawaliśmy po jednej formie słowa, a RCB używa innej właśnie przy kilku województwach. Alert wiszący godzinami bez odwołania jest teraz widoczny wprost (bez punktów), odwołanie „brak zagrożenia na terenie Polski” gasi wszystkie województwa, pozycja z MLAT nie udaje ADS-B, a wykaz punktów schronienia jest ze stanu z 21 września (86 388 miejsc). Szczegóły: docs/RELEASE_1.7.80.md.

Wersja 1.7.79: odwołanie alarmu przez RCB nie jest już liczone jako alarm, a kolor województwa w historii bierze się z poziomu alarmu, nie z samych punktów. Pierwsze wydanie cięte z jednego commita dla Androida i iPhone'a. Szczegóły: docs/RELEASE_1.7.79.md.

Wersja 1.7.78: regulacja głośności sygnału uwagi i naprawiona hierarchia dźwięków, alert RCB czytany z całej treści komunikatu, godzina w powiadomieniu, a pasek historii nie pokazuje już czerwonego tam, gdzie alarm był żółty. Szczegóły: docs/RELEASE_1.7.78.md.

Wersja 1.7.76: cała aplikacja mówi po ukraińsku — ekrany, karty obiektów, historia, ekran alarmu i opisy źródeł. Brakujące tłumaczenie spada na angielski, nie na pusty napis. Szczegóły: docs/RELEASE_1.7.76.md.

Wersja 1.7.74: czerwony alarm wymaga potwierdzenia — same 4 punkty nie wystarczą bez alertu RCB „znajdź bezpieczne miejsce” albo obiektu uderzeniowego kursem na Polskę. Alert RCB punktowany według treści (1,5 / 3 / 4,5 pkt), drony rozpoznawcze 0,5 → 0,15 pkt. Szczegóły: docs/RELEASE_1.7.74.md.

Wersja 1.7.72: GROTA mówi po angielsku i ukraińsku, a pobrana mapa jednego województwa nie gubi już ulic poza nim. Szczegóły: docs/RELEASE_1.7.72.md.

Wersja 1.7.70: zdjęcie z góry na karcie punktu schronienia znowu się wyświetla — usługa ortofotomapy GUGiK zmieniła sposób działania, a Androidy starsze niż 14 nie ufały certyfikatowi Geoportalu. Szczegóły: docs/RELEASE_1.7.70.md.

Wersja 1.7.68: nowy moduł GROTA. Po potwierdzeniu alarmu przycisk „Gdzie się schronić” otwiera najbliższe punkty schronienia z publicznego wykazu PSP, z odległością i trasą; wykaz działa bez internetu. Szczegóły: docs/RELEASE_1.7.68.md.

Wersja 1.7.67: aplikacja pamięta wybrany widok mapy (2D albo 3D), a gdy mapa nie wczyta się w 20 sekund, zamiast pustego ekranu pojawia się wyjaśnienie. Szczegóły: docs/RELEASE_1.7.67.md.

Wersja 1.7.66: przyciski mapy chowają się strzałką, aktywny alert RCB nie jest już brany za odwołany, a artykuły powtarzające jego treść nie dokładają drugich punktów za tę samą informację. Szczegóły: docs/RELEASE_1.7.66.md.

Wersja 1.7.65: na części nowych telefonów górny pasek wchodził pod zegar i ikony powiadomień. Telefon, który nie pozwala rysować map, pokazuje wyjaśnienie zamiast pustego ekranu — alarmy, sygnały i historia działają także bez mapy. Szczegóły: docs/RELEASE_1.7.65.md.

Wersja 1.7.64: naprawiona aktualizacja na Androidzie 9 i 10. Błąd „podpis aktualizacji nie zgadza się” nie był włamaniem — podpis był w porządku, to aplikacja źle go odczytywała. Szczegóły: docs/RELEASE_1.7.64.md.

Wersja 1.7.63: koniec stałego połączenia z serwerem. Aplikacja pyta o stan i dołącza znacznik wersji, którą już ma; gdy nic się nie zmieniło, odpowiada Cloudflare ze swojego brzegu. Do serwera trafia najwyżej jeden stan na dwie sekundy na centrum danych, niezależnie od liczby telefonów. Szczegóły: docs/RELEASE_1.7.63.md.

Wersja 1.7.62: historia nie gubi już godzin spędzonych w tle — zminimalizowana aplikacja nic nie nagrywa, więc po powrocie dociąga brakujący okres z serwera. Szczegóły: docs/RELEASE_1.7.62.md.

Notatki wszystkich wcześniejszych wydań leżą w katalogu docs/ jako pliki RELEASE_*.md.

Nieoficjalne wczesne ostrzeganie o zagrożeniach powietrznych

Fuzja kilku niezależnych sygnałów dla Polski, z priorytetem dla ściany wschodniej. Żaden pojedynczy sygnał nie jest rozstrzygający — dopiero kombinacja podnosi wiarygodność ostrzeżenia.

Instrukcja po polsku · English user guide · Інструкція українською

Instrukcja dla 1.7.79 opisuje „Moje miejsca”, rozdział alertów wojewódzkich i lokalnych obliczeń na pierwszym planie, regulację głośności żółtego sygnału oraz bibliotekę fotografii PL/EN/UA. Zrzuty otwierają się w pełnym rozmiarze.

⬇ Pobierz na Androida (APK) · ⬇ Pobierz na iOS (App Store) · ☕ Postaw kawę

📖 Instrukcja: Android · iPhone · English (Android) · English (iPhone) · Українська (Android)

Warning

NIEOFICJALNE źródło dodatkowe. Nie zastępuje syren, alertów RCB ani RSO. W razie realnego zagrożenia kieruj się oficjalnymi kanałami. Aplikacja korzysta ze źródeł publicznych, w tym crowdsourcingowych, które mogą się mylić, spóźniać lub milczeć.


Co to robi

Aplikacja zbiera sygnały z kilku niezależnych źródeł, przydziela im punkty i sumuje w oknie 60 minut (pełna waga przez 30 minut, potem liniowe wygaszanie) osobno dla każdego województwa. Przy ≥ 2 pkt włącza podwyższoną uwagę (sygnał uwagi i powiadomienie). Głośny alarm z syreną wymaga ≥ 4 pkt ORAZ potwierdzenia: Alertu RCB o treści „znajdź bezpieczne miejsce" albo obiektu uderzeniowego kursem na Polskę ≤ 15 minut od granicy (albo ≤ 50 km). Sama suma punktów z sygnałów pośrednich nie zapala czerwonego (zmiana 23.09.2026). UI zawsze pokazuje pełne rozbicie: które sygnały, skąd, ile punktów.

Sygnał Warunek Punkty
NEPTUN obiekt kursem na granicę PL — punktacja zależna od typu, liczby, odległości i liczby potwierdzeń (niżej) 0–8
NEPTUN oficjalny alarm powietrzny w obwodzie UA graniczącym z PL +1
Media/RSS obiekt + zdarzenie: 1 pkt; jednoznaczna bieżąca relacja operacyjna: 1,5 pkt; historia, ćwiczenia i następstwa prawne: 0 pkt. Całe RSS ma limit 1,5 pkt i samo nie alarmuje 0 / +1 / +1,5
RCB / RSO Alert RCB o zagrożeniu z powietrza — waga zależna od treści: „sytuacja jest monitorowana” 1,5; „trwa zmasowany atak” 3; „znajdź bezpieczne miejsce” 4,5. Źródłem jest RSO, a treść komunikatu dnia na gov.pl/web/rcb dokłada województwa, których RSO nie przekazało; sama lista wpisów gov.pl to tylko punkt odniesienia w czasie (0 pkt) +1,5 / +3 / +4,5
ADS-B ≥3 maszyny wojskowe nad województwem i >2× baseline z tej samej pory doby z 7 dni +1
PAŻP rzadka strefa ADHOC/R/NPZ/D obejmująca całą kolumnę od ziemi w górę; TRA/TSA/MRT/ATZ i designatory powtarzane w ciągu 7 dni nie punktują +0,5
Media LT/LV/EE incydent powietrzny wg mediów bałtyckich → podlaskie + warmińsko-mazurskie; komunikat kończący wygasza wkład tego samego zdarzenia +1
Sąsiedzi (RO/EE/LT) aktywne zamknięcie przestrzeni u sąsiada NATO — sygnał obserwacyjny, wyprzedzający +0,3

Punktacja obiektów NEPTUN

Jeden Shahed 80 km od granicy to co innego niż sześć Shahedów 50 km od granicy, a lokalny dron FPV nie jest punktowany w tym modelu — nie oznacza to, że jest nieszkodliwy. Zamiast jednej stawki za „obiekt kursem na PL" punkty uwzględniają kilka czynników:

punkty = waga_typu × √liczba × k_odległości × k_wiarygodności × k_potwierdzeń × k_cyklu × k_kursu
Czynnik Wartości
waga typu balistyczna 3,0 · MiG-31K 2,6 · manewrująca 2,4 · KAB 1,8 · Shahed 1,4 · dron 1,1 · zwiadowczy 0,5 · FPV 0
liczba (count) pierwiastek — cztery obiekty ważą 2× tyle co jeden, nie 4×
odległość płynna interpolacja: 0 km ×1,7 · 15 ×1,6 · 45 ×1,3 · 80 ×1,0 · 110 ×0,7 · 150 ×0,4 · 200 ×0,25 · 250 ×0,1; od 250 km wkład 0
wiarygodność high ×1,0 · medium ×0,6 · low ×0,35
potwierdzenia (sourceCount) 1 ×0,7 · 2 ×0,9 · 3–4 ×1,1 · ≥5 ×1,25
cykl życia confirmed ×1,1 · uncertain ×0,85 · created ×0,7

Wkład całego NEPTUN-a ograniczony do 8 pkt — przy kilkudziesięciu obiektach suma i tak dawno przekroczyła próg alarmu, a trzycyfrowa punktacja psułaby skalę.

Historyczna kalibracja (wcześniejsza krzywa odległości). Poniższe wyniki opisują wcześniejszy model i nie są aktualną tabelą progów. Obecny algorytm ma płynną krzywą, współczynnik kursu, minimum dla ciężkich obiektów przy granicy i progi ETA opisane w aktualnej instrukcji. Wagi dobrano na żywych danych NEPTUN i sprawdzono na udokumentowanych zdarzeniach oraz na 354 migawkach zebranych przez backend (1998 obserwacji obiektów w 7,5 h):

Scenariusz Punkty Reakcja
masowe naruszenie granicy (~19 dronów blisko) 8,0 alarm
rakieta manewrująca 25 km od granicy 4,7 alarm
6 Shahedów 50 km, 5 potwierdzeń 6,1 alarm
rutynowy nalot na zachodnią Ukrainę (110–130 km) 1,3 brak reakcji
pojedynczy dron 90 km, jedno zgłoszenie 0,4 brak reakcji
FPV tuż przy granicy 0,0 brak reakcji
zebrana historia (wszystkie obiekty ≥ 542 km) 0,0 brak reakcji

Klasyfikacja mediów ma trzy jawne wyniki (textmatch.py): 0 pkt dla ćwiczeń, administracji, publicystyki, historii oraz postępowań prawnych po zdarzeniu; 1 pkt dla jednoczesnego obiektu powietrznego i zdarzenia (AIR + EVENT); 1,5 pkt dla jednoznacznej bieżącej reakcji operacyjnej, np. alarmu powietrznego, syren, poderwania lotnictwa, zestrzelenia lub upadku obiektu. Sama fraza „naruszenie przestrzeni powietrznej” jest niejednoznaczna czasowo i należy do poziomu 1 pkt. Łączny wkład całej klasy RSS jest ograniczony do 1,5 pkt, więc same artykuły nie mogą uruchomić żółtego progu. Wykluczenia mają pierwszeństwo. Filtry mogą się mylić. Jedna klasa źródła ma limit wkładu do sumy (media ≤1,5, RCB ≤2, ADS-B ≤1, PAŻP ≤1, sąsiedzi ≤0,6) — pięć artykułów o tym samym zdarzeniu to wciąż jedno potwierdzenie. Nadmiarowe sygnały są widoczne w UI z przekreśloną punktacją. Artykuł rozpoznany po treści, regionie i czasie jako powtórzenie świeżego Alertu RCB pozostaje widoczny, ale wnosi 0 pkt; sama wzmianka o RCB nie wycina artykułu z nową informacją.

Alarm czasowy NEPTUN. Dla obiektu o znanym albo wiarygodnie wyliczonym kursie, średniej/wysokiej pewności i co najmniej dwóch potwierdzeniach działa dodatkowe zabezpieczenie ETA do granicy Polski, nie adresu użytkownika: żółty przy konserwatywnym czasie ≤10 min, czerwony przy ≤5 min. Od surowego czasu odejmowane jest 2,5 min (p90 opóźnienia źródła z pomiaru 27–30.08.2026). Brak kursu, niska pewność lub jedno zgłoszenie nie mogą samodzielnie uruchomić alarmu ETA.

Propagacja jest kaskadowa: region z sumą ≥ 2 pkt po wyłączeniu regionalnych Alertów RCB/RSO przekazuje 40 % pozostałego wyniku sąsiadom, ci 40 % tego swoim sąsiadom i tak dalej, licząc po najkrótszej drodze (BFS) aż wkład spadnie poniżej 0,1 pkt. Alarm 5 pkt w lubelskim rozkłada się więc tak: sąsiedzi +2,0 (żółty próg), drugi krąg +0,8, trzeci +0,3, czwarty +0,1. Oficjalny nadawca sam wskazuje obszar Alertu RCB, więc ten wkład nie jest powielany u sąsiadów. Pozostałe zagrożenie na wschodzie podnosi czujność w całym kraju proporcjonalnie do odległości. Każdy wkład jest osobnym sygnałem „Przeniesienie z woj. X (… , 2. krąg)", więc nigdy nie miesza się z własnym sygnałem regionu.

Architektura

[Neptun WS] ──┐                                    ┌─ aplikacja Android (push FCM per województwo)
[RSS media] ──┤   backend FastAPI na VPS           ├─ straznik.eu (mapa 3D w przeglądarce)
[RCB gov.pl]──┼─► fuzja punktowa ─► SQLite ─► API ─┤
[ADS-B mil] ──┤   progi 2 / 4 pkt   + WebSocket    ├─ ntfy / Telegram / Web Push
[PAŻP AUP*] ──┘   (za Cloudflare, HTTPS)           └─ fallback: wbudowany silnik w apce

Aplikacja domyślnie korzysta z serwera (https://straznik.eu): fuzja liczona jest raz na serwerze, a nie na każdym telefonie osobno — mniejsze zużycie baterii i darmowych limitów API. Gdy serwer jest niedostępny, aplikacja schodzi na wbudowany silnik (frontend/engine.js — lustrzana kopia logiki fuzji w JS; natywne żądania HTTP z WebView omijają CORS) jako fallback.

Powiadomienia push (FCM). Serwer przy wzroście poziomu wysyła wiadomość na temat voiv_<region>; telefon subskrybuje temat swojego województwa i dostaje alarm nawet przy zamkniętej aplikacji, wygaszonym ekranie i w trybie Doze — bez usługi działającej w tle (Android 15/16 taką usługę pierwszoplanową i tak ubijał, więc została wycofana). Poziom czerwony wyzwala pełnoekranowy alarm nad blokadą (AlarmActivity), żółty — powiadomienie heads-up.

Wdrożenie. Backend działa na VPS, wystawiony tunelem Cloudflare pod https://straznik.eu (TLS na brzegu Cloudflare, bez otwierania portu na origin). Klucz konta serwisowego FCM leży poza repozytorium, w backend/data/ (.gitignore).

Alarmy obwodów UA. Neptun wysyła ramki alerts WebSocketem; backend utrzymuje to gniazdo stale, więc oficjalne alarmy powietrzne w obwodach UA graniczących z PL docierają na bieżąco i są punktowane (ua_alert_border). Stan źródła widać w health.ua_alerts i na diodzie „Alarmy UA".

Historia 12 h — przewijana po stronie klienta. Zamiast pytać serwer o każdą pozycję suwaka (/api/history?at= — przy wielu użytkownikach przewijających naraz mnożyło zapytania i obciążało VPS), aplikacja pobiera całą historię raz (/api/history/bundle: migawki pozycji + surowe sygnały okna) i trzyma ją w pamięci (RAM), nie na dysku. Suwak liczy fuzję dla każdej chwili lokalnie tym samym accumulate co silnik offline (engine.js historyFrom/timelineFrom), więc przewijanie jest płynne i nie generuje ruchu do serwera. Bufor to okno kroczące 12 h (~0,5–2 MB), samo się przycina i odświeża z żywego feedu WebSocket (te same dane, które i tak płyną do mapy) — otwarta godzinami apka nie dociąga nic dodatkowego. Tryb offline trzyma migawki w localStorage (też okno 12 h). Stary backend bez /api/history/bundle jest znoszony łagodnie (krótsza historia).

* PAŻP: airspace.pansa.pl nie ma udokumentowanego API, ale jego mapa karmi się publicznym GeoJSON-em — /map-configuration/uup i /map-configuration/aup (adresy wskazuje /meta/configuration). Kolektor bierze stamtąd geometrię stref, okna rezerwacji i pułapy, a przypisanie do województwa liczy przez point-in-polygon na centroidzie strefy.

Uruchomienie backendu (Windows)

Instrukcje w tej sekcji służą autorowi i posiadaczom licencji. Samodzielne uruchamianie lub rozpowszechnianie Strażnika wymaga licencji autora (zob. Licencja).

cd backend
py -m pip install -r requirements.txt
copy .env.example .env     # uzupełnij NTFY_TOPIC itd.
py -m uvicorn app.main:app --host 0.0.0.0 --port 8600 --app-dir .

Dashboard: http://localhost:8600 · API: /api/state, /api/health, /api/history/bundle, /api/health/critical

Produkcyjnie backend działa na VPS na porcie 40141, wystawiony tunelem Cloudflare pod https://straznik.eu. Push FCM wymaga klucza konta serwisowego w backend/data/fcm-service-account.json (zob. „Powiadomienia").

Test warstwy Neptun bez serwera:

cd backend
py -m app.cli neptun    # strumień WS na żywo z oceną odległości/kursu do granicy PL
py -m app.cli score     # jednorazowy snapshot REST

Test fuzji end-to-end (endpoint domyślnie wyłączony — najpierw ustaw TEST_SIGNAL_ENABLED=true w .env, żeby nie był publicznie dostępny na produkcji):

curl -X POST http://localhost:8600/api/test-signal -H "Content-Type: application/json" -d "{\"voivodeship\":\"lubelskie\",\"points\":2.5,\"title\":\"test\"}"

Tryb wbudowany w przeglądarce: http://localhost:8600/?standalone=1

Powiadomienia

  • FCM (push do aplikacji Android) — główna ścieżka. Serwer przy wzroście poziomu wysyła wiadomość data na temat voiv_<region>; aplikacja subskrybuje temat swojego województwa (BackgroundPlugin.syncFcmSubscription) i dostaje alarm nawet przy zamkniętej aplikacji. Wymaga projektu Firebase: pliku google-services.json w android-app/android/app/ oraz klucza konta serwisowego na serwerze w backend/data/fcm-service-account.json (.gitignore). Włączane flagą FCM_ENABLED (domyślnie true). Poziom czerwony → pełnoekranowy alarm z syreną; żółty → heads-up.
  • ntfy: zainstaluj aplikację ntfy, wymyśl długi losowy temat, wpisz go w .env (NTFY_TOPIC=) i zasubskrybuj w aplikacji. Poziom WYSOKI idzie z priorytetem urgent.
  • Telegram: @BotFather → /newbot → token do .env; napisz do bota, odczytaj chat_id z https://api.telegram.org/bot<TOKEN>/getUpdates.
  • Web Push (VAPID): przycisk 🔔 w dashboardzie/na straznik.eu (wymaga http://localhost lub HTTPS). Ta sama ścieżka obsłuży PWA na iOS 16.4+ (po „Dodaj do ekranu początkowego"). Subskrypcja zawiera wyłącznie listę obserwowanych województw — bez nazw miejsc, adresów i GPS. Trwale odrzucone endpointy są usuwane, a ponowne otwarcie strony aktualizuje przypisanie regionów.

Tryb cienia progresji

Backend obserwuje na żywych danych hipotetyczne dodatkowe stopnie 2,5 / 3,0 / 3,5, ale nie łączy ich z żadnym kanałem powiadomień. Rejestruje również eksperymentalny stopień oznaczony 1,5 dla świeżego, ciągłego śladu obiektu lecącego w stronę Polski. Zasięg zależy od typu: do 250 km dla rakiet i MiG-31K, 120 km dla KAB, 100 km dla dronów/Shahedów oraz 60 km dla obiektu rozpoznawczego. Drugi wariant to wynik 1,5–2,0 potwierdzony przez co najmniej dwie niezależne klasy źródeł, w tym NEPTUN/alarm UA, ADS-B albo PAŻP. Obejmuje to dostępne dziś klasy wzmożonej czujności: wiarygodny obiekt lecący ku Polsce (rakieta, pocisk, KAB, Shahed/dron, nosiciel lub rozpoznanie) oraz zbieżność alarmu przy granicy, nietypowego ruchu wojskowego ADS-B, istotnej strefy PAŻP, sygnału sąsiedniego i mediów. Nie każdy z nich wystarcza sam: pozycje przybliżone, grupy, obiekt lecący od Polski, pojedynczy RSS, sama propagacja, stare obserwacje i pierwszy niepotwierdzony meldunek nie kwalifikują stopnia. Stan i próbki trafiają na 14 dni do tabel SQLite escalation_shadow_state oraz escalation_shadow_events.

ESCALATION_SHADOW_ENABLED=false wyłącza obserwację. Nawet po jej włączeniu moduł nie importuje warstwy powiadomień i nie wysyła push, dźwięku ani alarmu.

Oficjalne alarmy lotnicze RCB/RSO są ponadto zapisywane jako punkty odniesienia. Dla każdego nowego komunikatu backend zachowuje 30 minut wcześniejszych klatek mapy, sygnałów, punktacji i kandydatów trybu cienia. Osobno przechowuje surowy valid_from RSO, jego znormalizowany czas oraz chwilę pierwszego wykrycia na VPS. valid_from nie jest dowodem doręczenia SMS użytkownikowi; publiczne dane nie ujawniają takiego czasu. Wpisy zastane podczas startu są oznaczone jako niekwalifikujące się do pomiaru wyprzedzenia. Dane referencyjne są zachowywane 30 dni w rcb_reference_events, bez wpływu na wynik i wysyłkę.

RCB_REFERENCE_AUDIT_ENABLED=false wyłącza ten audyt.

Podpisywanie wydania

Instrukcje w tej sekcji służą autorowi i posiadaczom licencji. Samodzielne uruchamianie lub rozpowszechnianie Strażnika wymaga licencji autora (zob. Licencja).

Każde APK musi być podpisane, a Android przyjmie aktualizację tylko wtedy, gdy jest podpisana tym samym kluczem co wersja już zainstalowana. Buildy debug używają klucza debug.keystore o publicznie znanym haśle (android), który narzędzia potrafią zregenerować — na nim nie da się utrzymać ciągłości aktualizacji. Build debug ma włączoną flagę debuggable; zaufanie certyfikatom wynika osobno z konfiguracji sieci, nie z samego rodzaju podpisu.

Klucz tworzy się raz. Jego utrata oznacza, że użytkownicy nie zainstalują żadnej kolejnej wersji bez odinstalowania aplikacji (i utraty ustawień), więc zrób kopię pliku i zapisz hasła w menedżerze haseł.

cd android-app/android
"C:/Program Files/Android/Android Studio/jbr/bin/keytool" -genkeypair -v -keystore straznik-release.jks -alias straznik -keyalg RSA -keysize 4096 -validity 10000

Polecenie zapyta o hasło (dwa razy) i o dane właściciela — wystarczy imię lub nazwa projektu, reszta może zostać pusta. Następnie:

cp keystore.properties.example keystore.properties

…i wpisz w nim swoje hasła. Plik keystore.properties, *.jks i *.keystore są w .gitignore, więc nie trafią do repozytorium.

Budowanie podpisanego wydania:

cd android-app/android
JAVA_HOME="C:/Program Files/Android/Android Studio/jbr" ./gradlew assembleRelease

Wynik: app/build/outputs/apk/github/release/app-github-release.apk. Weryfikacja podpisu:

"$ANDROID_HOME/build-tools/37.0.0/apksigner" verify --print-certs -v app/build/outputs/apk/github/release/app-github-release.apk

Bez keystore.properties build wydania nadal się wykona, ale APK nie zostanie podpisany — to celowe, żeby wydanie nigdy nie wyszło z kluczem debug.

Od wersji 1.7.12 aplikacja ufa wyłącznie systemowym certyfikatom i blokuje zewnętrzny HTTP. Jedyny wyjątek to dokładnie localhost: wirtualny interfejs Capacitor, pozostawiony pod HTTP dla zachowania ustawień użytkowników. Sieć lub antywirus przechwytujący TLS certyfikatem użytkownika może blokować pobieranie danych. Nie wyłączamy weryfikacji certyfikatów jako obejścia. Zmiana wymaga nowego APK; starsze wydanie 1.7.11 nadal ufa certyfikatom użytkownika. Samo zaktualizowanie serwera nie zmienia jego zabezpieczeń.

Przebudowa APK

Instrukcje w tej sekcji służą autorowi i posiadaczom licencji. Samodzielne uruchamianie lub rozpowszechnianie Strażnika wymaga licencji autora (zob. Licencja).

cd android-app
rm -rf www && cp -r ../frontend www && rm www/sw.js
npx cap sync android
cd android && JAVA_HOME="C:/Program Files/Android/Android Studio/jbr" ./gradlew assembleRelease

Wynik: android-app/android/app/build/outputs/apk/github/release/app-github-release.apk. Po testach i sprawdzeniu podpisu wydania kopiujemy go jako Straznik.apk. Nigdy nie publikujemy app-debug.apk jako wydania. Przed publikacją sprawdź apksigner verify --print-certs, brak debuggable oraz skompilowaną konfigurację sieci. Aktualizacja musi zachować certyfikat podpisujący poprzednie wydanie.

Push FCM wymaga pliku android-app/android/app/google-services.json (z projektu Firebase) — bez niego wtyczka google-services się nie aktywuje i push nie działa. Na maszynie z antywirusem skanującym TLS (Avast/Kaspersky/ESET) Gradle może nie pobrać zależności Firebase (PKIX path building failed) — trzeba wskazać JVM magazyn certyfikatów z CA antywirusa (import certu do kopii cacerts + -Djavax.net.ssl.trustStore=…); po jednorazowym pobraniu deps wpadają do cache.

Struktura

  • backend/app/collectors/ — neptun.py (WS+REST), rss_media.py, rcb.py, adsb.py, pansa.py
  • backend/app/fusion.py — silnik punktowy (przejrzysty, nie ML)
  • backend/app/geo.py — punkty referencyjne granicy, haversine, ocena kursu
  • backend/data/straznik.db — SQLite: pełny log sygnałów (ts, źródło, punkty, województwo)
  • frontend/ — mapa 3D MapLibre GL, panel sygnałów, legenda, ekran „O aplikacji"
  • frontend/engine.js — wbudowany silnik (fallback, gdy serwer niedostępny)
  • backend/app/notify.py — kanały powiadomień: FCM (tematy per województwo), ntfy, Telegram, Web Push (VAPID)
  • android-app/ — opakowanie Capacitor (WebView) + projekt Gradle
  • android-app/android/app/src/main/java/pl/straznik/app/ — warstwa natywna: StraznikFcmService (odbiór pushy FCM → powiadomienie/alarm), Alarms (kanały powiadomień i budowa alarmu), AlarmActivity (pełnoekranowy alarm nad blokadą), BackgroundPlugin (most do JS: subskrypcja tematów FCM, zgody na powiadomienia i alarm pełnoekranowy), MainActivity
  • android-app/android/app/google-services.json — konfiguracja Firebase (niesekretna)
  • docs/ — instrukcja użytkownika (GitHub Pages) i zrzuty ekranu
  • scripts/build_cams.py — odświeżanie listy kamer
  • scripts/build_sounds.py — generowanie dźwięków alarmów do res/raw/

Zgodność z urządzeniami

minSdk 24 (Android 7.0) — targetSdk 36 (Android 16). Obsłużone różnice: kanały powiadomień od API 26, uprawnienie POST_NOTIFICATIONS od API 33, zgoda USE_FULL_SCREEN_INTENT od API 34, wyjątek od optymalizacji baterii od API 23. Layout używa env(safe-area-inset-*), więc pasek nie chowa się pod wycięciem ani paskiem systemowym; na wąskich ekranach przyciski zwijają się do ikon. Testowane na fizycznym urządzeniu (Android 16) i emulatorze Pixel 7 (Android 14).

Alarmy przy zamkniętej aplikacji: FCM push, nie usługa w tle. Wcześniejsze wersje pilnowały źródeł natywną usługą pierwszoplanową (MonitorService), ale Android 15/16 agresywnie ją ubijał (Stop FGS timeout kilka sekund po starcie), więc została wycofana. Teraz alarm wysyła serwer przez FCM na temat voiv_<region>, a StraznikFcmService buduje z niego powiadomienie — działa przy zamkniętej aplikacji, w trybie Doze i po restarcie telefonu, bez usługi w tle i bez drenowania baterii. Gdy serwer jest niedostępny, aplikacja i tak działa na wbudowanym silniku (alarmy wtedy przy otwartej aplikacji).

Alarm pełnoekranowy (AlarmActivity.java) przy poziomie czerwonym działa jak połączenie przychodzące: zapala ekran, pokazuje się nad blokadą, miga (te same barwy i tempo co #alarm-overlay w CSS), gra syrenę w pętli i wibruje do czasu potwierdzenia. Jest natywny, nie w WebView — musi pojawić się także wtedy, gdy proces aplikacji nie działa, o ile system pozwoli na dostarczenie powiadomienia i jego pełnoekranową prezentację. Wyzwala go full-screen intent z powiadomienia FCM (StraznikFcmService).

Na Androidzie 14+ należy sprawdzić uprawnienie USE_FULL_SCREEN_INTENT w ustawieniach, również po aktualizacji. Bez niego pełny ekran nie jest gwarantowany, więc aplikacja prosi o zgodę w ustawieniach (⚙ → 🚨 Zgoda na alarm pełnoekranowy), przypomina o niej banerem „Napraw". Przy braku zgody pozostaje powiadomienie systemowe; aplikacja podejmuje próbę wybudzenia, ale nie gwarantuje zapalenia ekranu. Działanie zależy też od ustawień powiadomień, kanałów, trybu Nie przeszkadzać i ograniczeń systemu.

Dźwięki generuje scripts/build_sounds.py do res/raw/ — te same przebiegi, które otwarta aplikacja syntetyzuje w Web Audio (żółty: dwutonowy sygnał 740↔988 Hz, czerwony: modulowana syrena 380↔860 Hz przez filtr dolnoprzepustowy). Dzięki temu tło brzmi identycznie jak pierwszy plan. Po zmianie brzmienia w app.js uruchom skrypt ponownie. Kanały powiadomień mają sufiks wersji (-v3), bo raz utworzony kanał ignoruje późniejsze zmiany dźwięku.

Źródła fuzji: NEPTUN (obiekty + alarmy obwodów UA), media regionalne, ogólnopolskie i bałtyckie, RCB, PAŻP, strefy sąsiadów (RO płn./EE/LT — sygnał obserwacyjny, 0,3 pkt) oraz ADS-B (sygnał pomocniczy o wadze 1 pkt, wymaga tygodnia próbek do baseline). Wszystkie liczy backend. Rozpoznawanie województwa z tekstu obejmuje wszystkie 16 (VOIV_KEYWORDS), a jeden ogólnopolski kanał Google News pokrywa regiony bez własnego feedu.

Lista aktualności łotewskich sił zbrojnych (mil.lv) jest dodatkowo sprawdzana co 30 sekund jako instrumentacja bez punktów. Rejestruje początek i koniec oficjalnego zagrożenia, aby mierzyć opóźnienia mediów; sama nie może wywołać alarmu. Komunikaty bałtyckie typu „alert over / zagrożenie zakończone” również nie dodają punktów — wygaszają wcześniejszy wpis tego samego incydentu.

Region i kaskada. Fuzja obejmuje wszystkie 16 województw, ze zdarzeniem na wschodzie „przelewającym się" na sąsiadów (kaskada, config.VOIV_NEIGHBORS). Push dociera tylko o wybranym województwie — telefon subskrybuje temat voiv_<region> (bez wyboru: cztery przygraniczne), więc nie dostaje alertów o zdarzeniach po drugiej stronie kraju, a wkład z sąsiedztwa i tak podnosi jego poziom. Przykład: zdarzenie 5 pkt w lubelskim u użytkownika z ustawionym mazowieckim daje „PODWYŻSZONA UWAGA: woj. mazowieckie (2.0 pkt)" z rozbiciem „Przeniesienie z woj. lubelskie (5.0 pkt, sąsiad)".

Wcześniejsze wydanie sprawdzono na fizycznym urządzeniu (Android 16) przy zamkniętej aplikacji: żółty wystawia heads-up bez budzenia ekranu; czerwony przy wygaszonym i zablokowanym ekranie zapala go i pokazuje pełnoekranowy AlarmActivity nad blokadą z syreną, a potwierdzenie zatrzymuje dźwięk i wibrację. Testy bieżącej zmiany zabezpieczeń wykonano na emulatorze Pixel 7 / Android 14; nie są gwarancją działania każdego telefonu. Raport testów.

Aktualizacje poza Google Play

Aplikacja sprawdza GET /api/app-version, a po wykryciu nowego wydania może pobrać Straznik.apk bezpośrednio i otworzyć systemowy instalator Androida. Przed instalacją natywnie sprawdza SHA-256 pliku; Android dodatkowo wymaga podpisu tym samym kluczem autora. Zwykłą aktualizację można odłożyć przyciskiem „Później” do końca bieżącej sesji. Wydanie oznaczone w opisie GitHub niewidocznym markerem <!-- critical-update --> nie ma przycisku odłożenia. Systemowe potwierdzenie instalacji pozostaje obowiązkowe — aplikacja nigdy nie instaluje się po cichu.

Każde kolejne wydanie GitHub Release musi mieć krótki opis zmian w punktach. Aplikacja pokazuje maksymalnie trzy pierwsze punkty w oknie aktualizacji jako sekcję „Co się zmienia”; opisuj w nich efekt widoczny dla użytkownika, nie detale techniczne.

Ograniczenia (świadome)

  • NEPTUN to agregator OSINT/crowdsourcingowy, nie radar — UI zawsze pokazuje confidenceLevel i ±uncertaintyKm. Wymagana atrybucja „Dane: NEPTUN" jest w UI.
  • Neptun pokazuje zagrożenia nad Ukrainą — obiekt, który wleci w polską przestrzeń, znika z danych źródłowych; system służy jako wyprzedzenie, nie śledzenie.
  • ADS-B nie widzi lotnictwa nad Ukrainą (sprawdzone: 0 maszyn nad zachodnią Ukrainą przy 219 wojskowych globalnie). Wojsko UA i RU nie nadaje transponderów, przestrzeń jest zamknięta. Widać za to AWACS-y, tankowce i transportowce NATO nad Polską, Rumunią i Bałtykiem. To publiczne transpondery maszyn, które chcą być widoczne — nie namierzanie obiektów przeciwnika.
  • Oprócz globalnej listy oznaczonej przez dostawcę jako wojskowa Strażnik odpytuje dwa ograniczone obszary geograficzne nad krajami bałtyckimi i lokalnie wybiera znane typy, operatorów oraz callsigny wojskowe. Ogranicza to pominięcia wynikające z błędnej flagi w rejestrze, ale nie zmienia wagi ADS-B ani nie obejmuje maszyn z wyłączonym transponderem.
  • Myśliwców w akcji nie zobaczy żadne źródło ADS-B, jeżeli nie nadają jawnie — ani naziemne, ani satelitarne. Maszyny bojowe w misjach QRA nadają szyfrowany Mode 5 (IFF), a nie ADS-B; satelity (Aireon, Spire) odbierają dokładnie ten sam sygnał, więc zmiana dostawcy niczego nie doda. Multilateracja (MLAT) w ADSBexchange bywa w stanie wyliczyć pozycję maszyny nadającej tylko Mode S, ale i tak nie obejmie lotnictwa z wyłączonym transponderem. Dlatego ADS-B jest tu sygnałem pomocniczym o wadze 1 pkt, a nie podstawą alarmu.
  • Ślady lotu Neptuna są w praktyce puste (pole trail zawiera 0–2 punkty, zwykle zduplikowane). Dla pozycji nieoznaczonych jako przybliżone aplikacja może budować trajektorię z kolejnych obserwacji. Przy positionQuality=approx pokazuje wyłącznie rejon zgłoszenia: bez dead-reckoning, pozornej trasy i ETA. Usunięcie wpisu przez źródło nie określa, czy obiekt zestrzelono, utracono czy zgłoszono ponownie pod innym identyfikatorem.
  • Kamery tylko z Polski — 641 publicznych kamer miejskich i turystycznych (worldcam.pl) we wszystkich 16 województwach, w tym 582 plenerowe; każda zweryfikowana pobraniem świeżego obrazu przy budowie listy. Podglądu NIE pokazuję w aplikacji: regulamin worldcam.pl opisuje wyłącznie własne użycie miniatur przez serwis i nie daje zgody na wyświetlanie ich u kogoś innego (sprawdzone 03.10.2026). Kafelek otwiera kamerę u źródła. Pierwotnie użyłem kamer drogowych traxelektronik.pl — okazało się, że wymagają logowania. Listę odświeżysz skryptem scripts/build_cams.py. Kamer z Ukrainy świadomie nie podpinam: od 2022 r. transmisje na żywo są tam zakazane, bo umożliwiają korygowanie ostrzału.
  • Baseline ADS-B potrzebuje ~tygodnia zbierania próbek, wcześniej warstwa nie punktuje.
  • RSS/scraping może się zepsuć, gdy serwisy zmienią strukturę — status w LED-ach i /api/health.
  • Rozpoznawanie województwa z nagłówka jest heurystyczne. Opiera się na nazwach miast i regionów, więc pomija nazwy kolidujące ze słowami pospolitymi („piła", „żary", „hel", „brzeg"), a przy zbieżnościach („Chełm" i „Chełmno", „Radom" i „Radomsko") wygrywa pierwsze dopasowanie w kolejności listy. Regiony bez własnego kanału RSS pokrywa jedno ogólnopolskie zapytanie Google News, więc docierają do nich tylko mocne frazy („alarm powietrzny", „zawyły syreny").

Licencja

Od wersji 1.7.54: wszelkie prawa zastrzeżone (LICENSE). Aplikację możesz bezpłatnie pobierać i używać, a kod czytać i zgłaszać do niego uwagi. Kopiowanie kodu, wydawanie zmienionych wersji albo udostępnianie funkcji aplikacji innym wymaga pisemnej licencji od autora — dotyczy to także firm, organizacji i instytucji publicznych. Licencje dla firm i instytucji: zgłoszenie (Issue) w repozytorium.

Strażnik jest source-available, a nie open source. Na liście SPDX nie ma licencji o takich warunkach, więc nasza ma oznaczenie własne: LicenseRef-Straznik-1.0. GitHub pokazuje ją w związku z tym jako „Other”.

Wersje do 1.7.53 włącznie pozostają na licencji MIT. Biblioteki, mapy, zdjęcia i dane innych podmiotów mają własne licencje — zob. NOTICE.

Oprogramowanie jest udostępniane „tak jak jest", bez gwarancji: to nieoficjalne źródło dodatkowe, nie system ratunkowy.

Dane i atrybucja

Hosting serwera: Mikrus (od 17.09.2026 serwer przekazany przez Mikrusa na potrzeby projektu).

NEPTUN (agregator OSINT; obiekty i alarmy obwodów UA) · adsb.lol / opendata.adsb.fi (w trybie awaryjnym też airplanes.live) · airspace.pansa.pl · gov.pl/RCB · media regionalne, bałtyckie i sąsiadów (MD, RO, SK, CZ, SE, HU — obserwacja, bez punktów) · kamery worldcam.pl · mapa © CARTO, © OpenStreetMap

About

Strażnik — nieoficjalne wczesne ostrzeganie o zagrożeniach powietrznych dla Polski. Fuzja sygnałów NEPTUN, mediów, RCB, ADS-B i PAŻP + aplikacja Android.

Topics

Resources

Contributing

Security policy

Stars

41 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages