Skip to content

Latest commit

 

History

102 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SG Timer - Monitor sesji strzeleckiej

Aplikacja webowa do odczytu i monitorowania danych z timerów strzeleckich SG Timer poprzez Bluetooth Low Energy (BLE).

Strona: timer.pifpaf.fun | GitHub: enclude/www.timer.pifpaf.fun

Funkcje

  • Instalacja jako aplikacja (PWA) - strone mozna zainstalowac na telefonie/tablecie ("Dodaj do ekranu glownego" / "Zainstaluj aplikacje"); uruchamia sie wtedy w osobnym oknie, bez paska adresu
  • Dziala bez internetu - po pierwszym otwarciu aplikacja startuje offline: polaczenie z timerem, podglad na zywo, cache sesji i kody tymczasowe dzialaja bez sieci; internet jest potrzebny wylacznie do zapisu w bazie kalkulatora
  • Kody tymczasowe - kazda zakonczona sesja dostaje lokalny kod (np. 3-0147) odtwarzany tonami do kamery, nawet bez internetu; po kodzie mozna pozniej odnalezc wynik
  • Polaczenie Bluetooth - laczenie z timerem przez Web Bluetooth API
  • Podglad na zywo - biezacy czas i liczba strzalow w czasie rzeczywistym
  • Sterowanie sesja - Start / Stop sesji strzeleckiej
  • Start z opoznieniem - Start PAR z losowym opoznieniem 1-4s (PAR_SETUP)
  • Ustawienia PAR - limit czasu i limit strzalow zapisywane do timera (karta "Ustawienia PAR"); timer sam konczy sesje po osiagnieciu limitu; limity sa tez wysylane do bazy kalkulatora w osobnych polach (bez zmiany opisu)
  • Historia sesji - przegladanie sesji zapisanych w urzadzeniu z liczba strzalow i czasem trwania
  • Cache sesji - pobranie sesji z dzisiaj (lub z ostatnich 24h — do wyboru) wraz z listami strzalow do pamieci przegladarki (localStorage); pobrane sesje mozna przegladac i wysylac do kalkulatora bez polaczenia BLE — timer pozostaje wolny dla innych
  • Hurtowa wysylka do bazy - przycisk "Wyslij wszystkie do bazy" w karcie "Sesje z cache" zapisuje jednym kliknieciem wszystkie sesje z cache w bazie kalkulatora (bez toru i uczestnika — uzupelnia sie je pozniej w kalkulatorze); sesje, ktore juz sa w bazie (ten sam numer seryjny timera i ID sesji), nie sa dublowane, tylko oznaczane "w bazie #ID" wraz z torem/uczestnikiem pobranymi z bazy; wpisy zapisane z tej przegladarki maja link "edytuj w bazie"; opcja "Nadpisz sesje juz zapisane w bazie" aktualizuje istniejace wpisy danymi z timera (punktacja i wpisane w kalkulatorze tor/uczestnik zostaja)
  • Etykiety sesji w cache - kazdej sesji w cache mozna przypisac nazwe toru i uczestnika (ikona olowka); etykiety sa zapamietywane i uzywane przy wysylaniu do kalkulatora (maja pierwszenstwo nad formularzem "Dane do kalkulatora")
  • Auto-zapis po Stop - jesli nazwa toru i uczestnik sa wypelnione w "Dane do kalkulatora", zakonczona sesja (czasy, strzaly, splity) automatycznie zapisuje sie w cache z tymi etykietami — idealne przy obsludze kolejnych uczestnikow na tym samym torze
  • Lista strzalow - czasy i splity dla wybranej sesji
  • Wyslij do kalkulatora - przesyla dane serii do piro-kalkulator.pifpaf.fun — dostepne zarowno po zakonczeniu biezacej sesji, jak i z poziomu historii
  • Zapisz w bazie - zapisuje wynik (czas i liczba strzalow) bezposrednio do bazy kalkulatora bez przechodzenia przez formularz; po zapisie wyswietla ID wpisu — przyda sie gdy nie liczymy A/C/D, a sam czas i liczba strzalow wystarczy
  • Eksport i import cache - cala pamiec sesji mozna zapisac do pliku JSON i wczytac na innym urzadzeniu (import scala dane, nie kasuje tego, co juz jest)
  • Baner synchronizacji - informuje o trybie offline i o liczbie sesji czekajacych na wyslanie do bazy; przycisk "Wyslij zalegle do bazy" wysyla je jednym kliknieciem, gdy wroci internet
  • Wersja w stopce - hash commitu z linkiem do GitHub, generowany automatycznie przez CI

Wymagania

Przegladarka

Aplikacja wymaga przegladarki wspierajacej Web Bluetooth API:

  • Google Chrome
  • Microsoft Edge
  • Opera

Uwaga: Firefox i Safari nie sa wspierane.

Kompatybilne urzadzenia

  • SG Timer Sport
  • SG Timer GO

Aplikacja jest kompatybilna z BLE API w wersji 3.2.

Jak uzywac

  1. Otworz aplikacje w kompatybilnej przegladarce (opcjonalnie zainstaluj ja: menu przegladarki → "Zainstaluj aplikacje" / "Dodaj do ekranu glownego")
  2. Kliknij "Polacz z timerem" i wybierz urzadzenie (nazwa zaczyna sie od "SG-SST4")
  3. Po polaczeniu mozesz:
    • Rozpoczac sesje przyciskiem "Start" (natychmiastowy) lub "Start z opoznieniem" (losowe 1-4s)
    • Zatrzymac sesje przyciskiem "Stop"
    • Po zakonczeniu sesji kliknac "Wyslij do kalkulatora"
    • Przegladac zapisane sesje — lista wyswietla liczbe strzalow i czas trwania
    • Kliknac sesje historyczna, obejrzec strzaly i wyslac do kalkulatora (opis zawiera date sesji)
    • Kliknac "Pobierz sesje do cache" (zakres: "z dzisiaj" lub "z ostatnich 24h") — sesje zapisza sie w przegladarce; po rozlaczeniu mozna je dalej przegladac w karcie "Sesje z cache" i wysylac do kalkulatora
    • Po zawodach: "Wyslij wszystkie do bazy" — wszystkie sesje z cache trafiaja do bazy kalkulatora bez dublowania juz zapisanych; tor i uczestnika mozna uzupelnic pozniej linkiem "edytuj w bazie" lub w panelu kalkulatora
    • Kliknac "Zapisz w bazie" — zapisuje wynik wprost do bazy kalkulatora (bez A/C/D) i wyswietla ID wpisu
    • Ustawic "Nr stanowiska" w karcie "Dane do kalkulatora" — po kazdej sesji aplikacja nada i zagra kod tymczasowy (np. 3-0147), takze bez internetu
    • "Eksportuj do pliku" / "Wczytaj z pliku" w karcie "Sesje z cache" — kopia zapasowa sesji i przenoszenie ich miedzy urzadzeniami

Specyfikacja techniczna

BLE Service UUID

7520ffff-14d2-4cda-8b6b-697c554c9311

Charakterystyki BLE

Charakterystyka UUID Wlasciwosci Opis
Command 75200000-... W, N Wysylanie komend; odpowiedzi jako notyfikacje
Event 75200001-... N Odbieranie zdarzen z urzadzenia
Session List 75200002-... R, W Lista zapisanych sesji
Reserved 75200003-... R Zarezerwowany — nie zapisywac
Shot List 75200004-... R, W Lista strzalow w sesji
PAR Setup 75200005-... R, W Konfiguracja startu PAR (opoznienie, limit czasu, limit strzalow)
Unix Time 75200006-... R, W Czas urzadzenia (czas lokalny bez strefy)
API Version 7520fffe-... R Wersja API (ASCII)

Komendy

ID Nazwa Opis
0x00 SESSION_START Rozpocznij sesje
0x01 SESSION_SUSPEND Wstrzymaj sesje
0x02 SESSION_RESUME Wznow sesje
0x03 SESSION_STOP Zakoncz sesje

Zdarzenia

ID Nazwa Opis
0x00 SESSION_STARTED Sesja rozpoczeta
0x01 SESSION_SUSPENDED Sesja wstrzymana
0x02 SESSION_RESUMED Sesja wznowiona
0x03 SESSION_STOPPED Sesja zakonczona
0x04 SHOT_DETECTED Wykryto strzal
0x05 SESSION_SET_BEGIN Poczatek setu sesji

Numerowanie strzalow

Urzadzenie wysyla shotNum od 0. Aplikacja wyswietla strzaly od 1 (shotNum + 1). Pierwszy strzal (shotNum === 0) wyswietlany jest bez splitu (-).

Czas urzadzenia

Urzadzenie zapisuje czas lokalny jako Unix timestamp (bez informacji o strefie). Wyswietlanie uzywa timeZone: 'UTC', aby uniknac podwojnego dodania offsetu przez przegladarke.

Integracja z kalkulatorem

Przycisk "Wyslij do kalkulatora" otwiera piro-kalkulator.pifpaf.fun z parametrami GET:

Parametr Opis
liczba_strzalow Liczba strzalow w serii
czas_bazowy Czas ostatniego strzalu w sekundach (np. 15.80)
opis Opoznienie startu + lista strzalow z czasami i splitami (URL-encoded)
nazwa_toru Nazwa toru z pola "Dane do kalkulatora" (tylko gdy wypelnione)
uczestnik Uczestnik z pola "Dane do kalkulatora" (tylko gdy wypelnione)

Dostepny w dwoch trybach:

  • Biezaca sesja — pojawia sie po zakonczeniu sesji (SESSION_STOPPED), opis zaczyna sie od opoznienia startu (np. opoznienie startu 2.3s), dalej lista strzalow
  • Sesja historyczna — pojawia sie pod lista strzalow wybranej sesji, opis zaczyna sie od daty i godziny sesji, a nastepnie opoznienia startu (jesli zapisane w cache)

Opoznienie startu (delay od naciśniecia "Start") pochodzi ze zdarzenia SESSION_STARTED i jest dolaczane do opis dla sesji live oraz sesji z cache (gdzie jest trwale zapisywane). Sesje wczytane bezposrednio przez BLE ("Wczytaj sesje") nie zawieraja tej informacji — SHOT_LIST jej nie przekazuje.

Po polaczeniu z timerem widoczna jest karta "Dane do kalkulatora" z polami "Nazwa toru" i "Uczestnik". Nazwa toru jest zapamietywana w przegladarce (localStorage) i przywracana przy kolejnej wizycie; uczestnik jest wpisywany kazdorazowo. Oba pola sa opcjonalne — puste nie sa dolaczane do URL.

Zapis bezposrednio do bazy (bez punktacji)

Przycisk "Zapisz w bazie" pozwala zapisac wynik sesji wprost do bazy piro-kalkulator.pifpaf.fun bez otwierania kalkulatora i recznego wpisywania A/C/D. Przyda sie gdy interesuje nas sam czas i liczba strzalow, bez pelnej punktacji IPSC.

Przycisk Dostepnosc
"Zapisz w bazie" (biezaca sesja) pojawia sie po zakonczeniu sesji (razem z "Wyslij do kalkulatora")
"Zapisz w bazie" (historia/cache) pojawia sie pod lista strzalow wybranej sesji

Po kliknieciu:

  1. Przycisk blokuje sie i wyswietla "Zapisywanie..."
  2. Dane (liczba strzalow, czas, opis z lista strzalow i splitami, nazwa toru, uczestnik) sa wysylane przez POST na https://piro-kalkulator.pifpaf.fun/api_save.php
  3. Po sukcesie wyswietlane jest "Zapisano! ID: #123" — identyfikator wpisu w bazie kalkulatora
  4. W razie bledu komunikat pokazuje przyczyne i przycisk odblokowuje sie

Wynik zapisuje sie z zerami dla trafien A/C/D i wszystkich kar (hit_factor = 0). Pelne dane (lista strzalow z czasami i splitami) trafiaja do pola opis. Jesli sesja ma kod tymczasowy, jest on wysylany razem z wynikiem (pole temp_id) — po nim mozna potem odnalezc wpis.

Gdy zapis nie powiedzie sie z powodu braku internetu, komunikat brzmi "Brak internetu — sesja czeka w cache": nic nie ginie, sesje wysyla sie pozniej przyciskiem "Wyslij zalegle do bazy".

Praca bez internetu (PWA)

Aplikacja jest Progressive Web App — mozna ja zainstalowac i uzywac bez zasiegu.

Instalacja:

  • Android/Chrome: menu (trzy kropki) → "Zainstaluj aplikacje" lub "Dodaj do ekranu glownego"
  • Desktop Chrome/Edge: ikona instalacji w pasku adresu
  • Po instalacji aplikacja otwiera sie w osobnym oknie, w pionie, z wlasna ikona

Co dziala bez internetu:

  • otwarcie aplikacji (strona jest zapamietana przez service worker sw.js)
  • polaczenie z timerem, start/stop, podglad na zywo, historia sesji z timera
  • cache sesji w przegladarce, etykiety (tor/uczestnik), eksport do pliku
  • kody tymczasowe i ich sygnal tonowy

Czego bez internetu nie ma:

  • zapisu do bazy kalkulatora i wysylki do kalkulatora (te sesje czekaja w cache)
  • sygnalu tonowego z ID wpisu w bazie (ID powstaje dopiero przy zapisie)

Baner na gorze strony pokazuje tryb offline oraz liczbe sesji w cache, ktore nie maja jeszcze wpisu w bazie. Gdy internet wroci, baner daje przycisk "Wyslij zalegle do bazy" — nic nie jest wysylane samo z siebie, wysylka zawsze wymaga klikniecia.

Po wdrozeniu nowej wersji aplikacja aktualizuje sie sama przy kolejnym otwarciu z internetem (wersja w stopce pokazuje, ktory commit jest uruchomiony).

Kody tymczasowe (dzialaja bez internetu)

Sygnal z ID wpisu wymaga zapisu w bazie, czyli internetu. Na stanowisku strzeleckim zasiegu zwykle nie ma, dlatego kazda zakonczona sesja moze dostac kod tymczasowy nadawany lokalnie w telefonie i od razu odtwarzany tonami do kamery.

  • Kod ma postac S-NNNN, np. 3-0147: pierwsza cyfra to numer stanowiska, dalej licznik sesji w tej przegladarce. Dzieki numerowi stanowiska kody z roznych stanowisk sie nie powtarzaja.
  • Nr stanowiska ustawia sie raz, w karcie "Dane do kalkulatora" (wartosci 1-9, zapamietywane w przegladarce).
  • Checkbox "Zagraj kod tymczasowy po zakonczeniu sesji (dziala bez internetu)" jest domyslnie wlaczony. Po komendzie Stop kod pojawia sie przy sesji i jest odtwarzany; przycisk "🔊 Zagraj kod …" pozwala puscic go ponownie (np. gdy kamera wtedy nie nagrywala).
  • Sesja z nadanym kodem zawsze zapisuje sie w cache — takze gdy tor i uczestnik nie sa wypelnione (kod na nagraniu bez listy strzalow nie mialby wartosci).
  • Kod jest widoczny przy sesji w karcie "Sesje z cache" i trafia do bazy razem z wynikiem, wiec Piro Overlay potrafi po nim odnalezc wpis — nawet jesli ID wpisu nigdy nie zagralo.
  • Drugi checkbox, "Zapisz w bazie i zagraj sygnal ID po zakonczeniu sesji (wymaga internetu)", dziala jak wczesniej: po Stop sesja zapisuje sie w bazie i odtwarzany jest sygnal z ID wpisu. Oba sygnaly moga byc wlaczone naraz — nigdy nie nakladaja sie na siebie, graja po kolei.

Kopia zapasowa cache (eksport / import)

Cache sesji zyje w pamieci jednej przegladarki na jednym urzadzeniu — wyczyszczenie danych witryny skasowaloby caly dzien zawodow. W karcie "Sesje z cache" sa dwa przyciski:

  • "Eksportuj do pliku" — zapisuje wszystkie sesje (ze strzalami, etykietami, kodami tymczasowymi i numerami wpisow w bazie) do pliku sgtimer-cache-RRRR-MM-DD.json
  • "Wczytaj z pliku" — scala zawartosc pliku z tym, co juz jest w przegladarce: nowe sesje dopisuje, a w istniejacych uzupelnia tylko brakujace dane. Wlasne poprawki (np. poprawione nazwisko) i przypisane numery wpisow w bazie nie sa nadpisywane. Dzieki temu mozna scalic sesje z kilku tabletow na jednym urzadzeniu.

Sygnal tonowy ID (dla Piro Overlay)

Telefon moze odtworzyc identyfikator sesji jako sekwencje tonow - aplikacja Piro Overlay, nakladajaca info o strzalach na wideo, odczytuje ten sygnal z mikrofonu kamery i uzupelnia sesje automatycznie, bez recznego wpisywania.

Protokol (wersja 3): marker + cyfra kanalu + 4 cyfry wartosci + cyfra kontrolna, pasmo 5000-7000 Hz, kazdy ton 0,3 s, cala sekwencja powtarzana dwa razy.

Kanal Wartosc Kiedy
0 ID wpisu w bazie kalkulatora po zapisie w bazie (wymaga internetu)
1-9 kod tymczasowy (kanal = nr stanowiska) zaraz po zakonczeniu sesji, takze offline
  • Checkbox "Zapisz w bazie i zagraj sygnal ID po zakonczeniu sesji (wymaga internetu)" (karta "Dane do kalkulatora", domyslnie wylaczony, zapamietywany w przegladarce) - gdy zaznaczony, sesja po Stop zapisuje sie w bazie, a sygnal z ID gra automatycznie.
  • Przycisk "🔊 Zagraj sygnal ID" pojawia sie zawsze przy komunikacie "Zapisano!" (obok "Zapisz w bazie", tak przy sesji zywej, jak i historii/cache) - pozwala puscic sygnal jeszcze raz, np. gdy kamera nie nagrywala w danym momencie.
  • Dziala tylko dla wartosci 0-9999 (limit 4-cyfrowego protokolu) - dla wiekszych ID sygnal nie jest odtwarzany (zamiast odtworzyc ucieta, blednie wygladajaca wartosc).
  • Gdy graja oba sygnaly (kod tymczasowy i ID), ida jeden po drugim - nigdy sie nie nakladaja.

Uwaga dla integratorow: wersja 3 nie jest zgodna z wersja 2 (bez cyfry kanalu). Aplikacja, dekoder w Piro Overlay i kalkulator musza uzywac tych samych czestotliwosci i czasow.

PAR_SETUP

Charakterystyka 75200005-… (R, W), format: [start_delay(2), time_limit(2), shot_limit(2)]

Pole Wartosc Znaczenie
start_delay jednostki 0.1s 0x0000 = natychmiastowy, 0xFFFF = losowe 1.0–4.0s
time_limit jednostki 0.1s 0x0000 = bez limitu czasu
shot_limit liczba strzalow 0x0000 = bez limitu strzalow

Przycisk "Start" zapisuje PAR z zerowym opoznieniem, przycisk "Start z opoznieniem" z losowym opoznieniem 1.0–3.0s (losowanym w JS). W obu przypadkach time_limit i shot_limit pochodza z karty "Ustawienia PAR" (0 = bez limitu). Przycisk "Zapisz PAR w timerze" zapisuje same limity, zachowujac start_delay odczytany z urzadzenia. Przycisk "Zresetuj PAR" zeruje oba pola i zapisuje 0/0 do timera (usuwa limity). Po zapisie PAR_SETUP wymagane jest oddzielne wyslanie komendy SESSION_START.

Wersjonowanie

Stopka czyta wersje bezposrednio z katalogu .git (serwer jest wdrazany przez git pull w cronie): hash commitu z HEAD/refs jako klikalny link do GitHub oraz date wdrozenia (filemtime refa). Dostep HTTP do .git jest zablokowany w .htaccess. Gdy katalogu .git brak, wersja nie jest wyswietlana.

Ten sam hash steruje trybem offline: service worker jest rejestrowany jako sw.js?v=<hash>, wiec kazde wdrozenie to nowy adres workera i nowa kopia strony w pamieci offline (stare kopie sa kasowane). Pliki sw.js i manifest.json sa serwowane z Cache-Control: no-cache, zeby przegladarka nie trzymala w nieskonczonosc starej wersji aplikacji.

Testowane urzadzenia

Urzadzenie Firmware
SG-SST4B00000 BLE API 3.2

Historia testow

25.02.2026 — pierwsze testy, odkrycie bledow

  • Urządzenie: SG-SST4B00000, API 3.2
  • Sesje 8-strzalowe
  • Odkryte bledy:
    • shotNum 0-indexed — strzaly wyswietlane od 0 zamiast od 1
    • parseBigEndian zwracal -1 dla 0xFFFFFFFF (signed 32-bit overflow) — sentinel nie byl wykrywany, lista sesji ladowala 100 pustych wpisow z ID -1 i data 01.01.1970
    • formatDate bez timeZone:'UTC' — czas urzadzenia wyswietlany o 1h za duzo (CET podwojnie naliczany)

26.02.2026 — testy po poprawkach

  • Sesja 30 strzalow, czas 38.20s
  • Czas urzadzenia: 26.02.2026, 10:40:42 (telefon: 10:41) — zgodny po poprawce strefy
  • Licznik i komunikat "Sesja zakonczona (30 strzalow)" / "Strzaly: 30" — zgodne po poprawce numerowania
  • Przycisk "Wyslij do kalkulatora" pojawil sie poprawnie po zakonczeniu sesji
  • Dane przekazane do piro-kalkulator.pifpaf.fun:
    • czas_bazowy=38.2, liczba_strzalow=30
    • opis z pelna lista 30 strzalow z czasami i splitami, np. 1: 16.05s | 2: 19.23s (+3.18s) | ...
  • Kalkulator poprawnie wyswietlil wynik: czas koncowy 38.20s, 0 kar

Autor

pifpaf.fun

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages