This shows you the differences between two versions of the page.
pm:prj2025:ajipa:arthur.peter [2025/05/21 15:27] arthur.peter [Jurnal] |
pm:prj2025:ajipa:arthur.peter [2025/05/21 16:29] (current) arthur.peter [Rezultate Obţinute] |
||
---|---|---|---|
Line 71: | Line 71: | ||
**Functii adaugate:** | **Functii adaugate:** | ||
+ | ==ESP32-CAM== | ||
- | * | + | * onTimer() (ISR marcat cu IRAM_ATTR): |
+ | * Funcție de tip întrerupere (ISR) apelată de timer la un interval configurat (în exemplu, la 500 ms). Setează flag‑ul (motionCheckFlag) care indică faptul că trebuie verificată prezența mișcării. | ||
+ | * startRecording(): | ||
+ | * Creează un fișier nou pe cardul SD (nume incrementat automat) cu extensia .mjpeg. Pornește înregistrarea, reținând momentul de start, pentru a ști ulterior când să se oprească după un anumit interval (ex. 5 secunde). | ||
+ | * stopRecording(): | ||
+ | * Închide fișierul de înregistrare și setează indicatorul de înregistrare (isRecording) pe false. Resetează flag‑urile și memoria dedicată primei capturi, pentru a pregăti sistemul pentru o nouă înregistrare. | ||
+ | * downscaleGrayscale(const camera_fb_t *fb, uint8_t *output): | ||
+ | * Converteste cadrul JPEG (fb->buf) în format RGB și apoi îl reduce la o imagine 64×64 în tonuri de gri (8 biți/pixel). Folosește sampling 3×3 pentru a face o mică anti-aliasing și calculează media valorilor de gri. Returnează true/false în funcție de reușita procesării. | ||
+ | * detectMotion(const camera_fb_t *fb): | ||
+ | * Preia cadrul de la cameră, apoi îl trimite către downscaleGrayscale(). Compară rezultatul cu cadrul anterior (prevFrame) și calculează media diferențelor pixel cu pixel. Dacă media diferențelor depășește MOTION_THRESHOLD, consideră că s-a detectat mișcare și întoarce true. | ||
+ | * getLastFileNumber(): | ||
+ | * Scanează directorul rădăcină de pe cardul SD pentru a găsi fișiere de tipul motion_x.mjpeg. Caută cel mai mare număr x deja folosit în denumirea fișierelor și returnează următorul index disponibil. | ||
+ | * checkMotion(): | ||
+ | * Se apelează atunci când motionCheckFlag este setat de întrerupere (onTimer()). Obține un nou cadru de la cameră, apelează detectMotion() și dacă este detectată mișcare, pornește înregistrarea (startRecording()). | ||
+ | |||
+ | ==Aplicatie Mobila== | ||
+ | |||
+ | * onCreate() (în MainActivity) | ||
+ | * Configurează interfața grafică folosind Jetpack Compose. Creează un Scaffold și încarcă un Composable care afișează un WebView. | ||
+ | * onResume() (în MainActivity) | ||
+ | * La revenirea în aplicație, pornește un Coroutine care testează de mai multe ori dacă adresa camerei (ESP32) este accesibilă. Dacă e disponibilă, încarcă în WebView pagina de la URL-ul camerei; dacă nu, apelează promptToConnect() pentru a cere utilizatorului să se conecteze manual la rețeaua ESP32. | ||
+ | * WebViewContainer(setWebView: (WebView) -> Unit) | ||
+ | * O funcție de tip Composable care creează un WebView cu diverse setări activate: JavaScript, stocare DOM, acces la fișiere, redare media etc. Returnează prin callback obiectul WebView pentru a putea fi folosit ulterior. | ||
+ | * isCameraReachable() | ||
+ | * Funcție suspendată ce încearcă un request tip HTTP GET la adresa camerei (192.168.4.1). Verifică codul de răspuns (2xx înseamnă succes) și returnează true dacă dispozitivul este accesibil. | ||
+ | * promptToConnect(context: Context) | ||
+ | * Afișează un mesaj Toast care cere utilizatorului să se conecteze la WiFi-ul camerei și deschide setările de WiFi ale telefonului (Settings.ACTION_WIFI_SETTINGS). | ||
===== Rezultate Obţinute ===== | ===== Rezultate Obţinute ===== | ||
+ | |||
+ | Demo: https://www.youtube.com/watch?v=VeDdLXLpNBQ&ab_channel=ArthurPeter | ||
+ | |||