Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ss:laboratoare:03 [2025/02/25 22:21]
jan.vaduva [Resurse suplimentare]
ss:laboratoare:03 [2026/03/16 19:36] (current)
ciprian.popescu0411
Line 1: Line 1:
-====== Laborator 3: Implementarea unui pipeline CI/CD ======+====== Laborator 3: Captură și transmisie de imagini prin MQTT cu ESP32-CAM ​====== 
 + 
 +În acest laborator ne vom familiariza cu platforma de dezvoltare ESP32-CAM și vom implementa un sistem de supraveghere simplu care transmite imagini către un calculator prin protocolul MQTT.
  
 ===== Obiective ===== ===== Obiective =====
-  * Construirea și livrarea containerizată a aplicației dezvoltate în laboratoarele anterioare 
-  * Configurarea unui pipeline CI/CD pentru automatizarea procesului de build și deployment 
-  * Implementarea unui sistem de deployment automat în mediu de test/​production 
  
-===== Cerințe tehnologice ​===== +  - Înțelegerea arhitecturii unui sistem IoT bazat pe MQTT (Publisher/​Subscriber). 
-  * **Versionare cod**: GitHub/GitLab ​cu strategii ​de branching ​(Git Flow+  - Configurarea mediului de dezvoltare (PlatformIO,​ Mosquitto, Python). 
-  * **CI/CD Pipeline**: GitHub Actions/GitLab CI/CD/Jenkins +  - Utilizarea ESP32-CAM pentru captură foto și transmisie Wi-Fi. 
-  * **Containerizare**: DockerDocker Compose +  - Controlul dispozitivului de la distanță prin comenzi MQTT. 
-  * **Deployment**: Kubernetes ​(Minikube/MicroK8s) sau Docker Swarm+ 
 +===== Arhitectura sistemului ​===== 
 + 
 +Sistemul este compus din trei entități principale:​ 
 + 
 +  ​**ESP32-CAM (Publisher/​Subscriber)**: 
 +    * Se conectează la rețeaua Wi-Fi. 
 +    * Publică imagini (JPEG) pe topicul ''​ssproject/​images''​. 
 +    * Ascultă comenzi pe topicul ''​ssproject/​commands''​. 
 +  - **Broker MQTT (Mosquitto)**: 
 +    * Intermediarul care gestionează mesajele între cameră și calculator. 
 +    * Rulează local pe calculatorul vostru. 
 +  - **Client Python (Subscriber/Publisher)**:​ 
 +    * Afișează imaginile primite în timp real. 
 +    * Trimite comenzi către cameră (''​START-LIVE'',​ ''​STOP-LIVE'',​ ''​CAPTURE''​). 
 + 
 +===== Configurare mediu de lucru ===== 
 + 
 +Pentru a rula proiectul, trebuie să pregătim infrastructura software. 
 + 
 +==== 1. Brokerul MQTT (Mosquitto) ==== 
 + 
 +Dacă nu aveți un broker instalat, descărcați [[https://​mosquitto.org/​download/​|Mosquitto]]. 
 + 
 +Creați în rădăcina proiectului un fișier de configurare ''​mosquitto.conf''​ pentru a permite conexiuni externe (de la ESP32): 
 + 
 +<file text mosquitto.conf>​ 
 +listener 1883 
 +allow_anonymous true 
 +</​file>​ 
 + 
 +Porniți brokerul folosind acest fișier de configurare:​ 
 + 
 +<code bash> 
 +# Opriți serviciul default dacă rulează 
 +sudo systemctl stop mosquitto.service 
 + 
 +# Porniți brokerul ​cu configurarea noastră 
 +/​usr/​sbin/​mosquitto -c mosquitto.conf -v 
 +</​code>​ 
 + 
 +==== 2. Clientul Python (Receiver) ==== 
 + 
 +Aplicația ​de vizualizare ​(''​receiver.py''​necesită Python și câteva biblioteci. 
 + 
 +<code bash> 
 +# Creați mediul virtual (dacă nu există) 
 +python3 -m venv .venv 
 +source .venv/​bin/​activate 
 + 
 +# Instalați dependențele 
 +pip install paho-mqtt opencv-python numpy 
 +</​code>​ 
 + 
 +==== 3. Crearea proiectului PlatformIO (Firmware ESP32-CAM) ==== 
 + 
 +Vom crea un proiect PlatformIO de la zero pentru plăcuța ​**ESP32-CAM (AI-Thinker)**. 
 + 
 +=== 3.1 Instalare PlatformIO === 
 + 
 +Instalați extensia **PlatformIO IDE** din Visual Studio Code (Extensions → căutați "​PlatformIO IDE" → Install). 
 + 
 +=== 3.2 Crearea proiectului === 
 + 
 +Puteți crea proiectul din interfața PlatformIO sau din terminal: 
 + 
 +<code bash> 
 +mkdir camera && cd camera 
 + 
 +# Creați un mediu virtual Python și instalați PlatformIO CLI 
 +python3 -m venv .venv 
 +source .venv/bin/​activate 
 +pip install platformio 
 + 
 +# Inițializați proiectul 
 +pio project init --board esp32cam 
 +</​code>​ 
 + 
 +=== 3.3 Configurarea proiectului === 
 + 
 +Înlocuiți conținutul fișierului ''​camera/​platformio.ini''​ cu următorul:​ 
 + 
 +<file ini platformio.ini>​ 
 +; PlatformIO Project Configuration File 
 + 
 +[env] 
 +platform = espressif32 
 +framework = arduino 
 +lib_deps =  
 +    espressif/​esp32-camera@^2.0.4 
 +    WiFi @ ^2.0.0 
 +    knolleary/​PubSubClient @ ^2.8 
 +monitor_speed = 115200 
 + 
 +[env:​esp32cam] 
 +board = esp32cam 
 +build_flags = -D CAMERA_MODEL_AI_THINKER 
 +              -D MQTT_MAX_PACKET_SIZE=65000 
 +</​file>​ 
 + 
 +**Explicații:** 
 + 
 +  * ''​espressif/esp32-camera''​ — biblioteca oficială pentru modulul camerei. 
 +  * ''​knolleary/PubSubClient''​ — client MQTT pentru Arduino. 
 +  * ''​CAMERA_MODEL_AI_THINKER''​ — definește pinii GPIO corespunzători modelului AI-Thinker. 
 +  * ''​MQTT_MAX_PACKET_SIZE=65000''​ — mărește dimensiunea maximă a unui pachet MQTT (necesar pentru trimiterea imaginilor JPEG). 
 + 
 +=== 3.4 Definirea pinilor GPIO pentru cameră === 
 + 
 +Creați fișierul ''​camera/include/​camera_pins.h''​ cu definițiile pinilor GPIO pentru modelul AI-Thinker:​ 
 + 
 +<file c camera_pins.h>​ 
 +#if defined(CAMERA_MODEL_AI_THINKER) 
 +#define PWDN_GPIO_NUM ​    32 
 +#define RESET_GPIO_NUM ​   -1 
 +#define XCLK_GPIO_NUM ​     0 
 +#define SIOD_GPIO_NUM ​    26 
 +#define SIOC_GPIO_NUM ​    27 
 + 
 +#define Y9_GPIO_NUM ​      35 
 +#define Y8_GPIO_NUM ​      34 
 +#define Y7_GPIO_NUM ​      39 
 +#define Y6_GPIO_NUM ​      36 
 +#define Y5_GPIO_NUM ​      21 
 +#define Y4_GPIO_NUM ​      19 
 +#define Y3_GPIO_NUM ​      18 
 +#define Y2_GPIO_NUM ​       5 
 +#define VSYNC_GPIO_NUM ​   25 
 +#define HREF_GPIO_NUM ​    23 
 +#define PCLK_GPIO_NUM ​    22 
 + 
 +#else 
 +#error "​Camera model not selected"​ 
 +#endif 
 +</​file>​ 
 + 
 +=== 3.5 Structura finală === 
 + 
 +După acești pași, structura proiectului ar trebui să arate astfel: 
 + 
 +<code text> 
 +camera/ 
 +├── include/ 
 +│   ​└── camera_pins.h ​      # Definițiile pinilor GPIO 
 +├── src/ 
 +│   ​└── main.cpp ​           # Codul principal (de mai jos) 
 +├── platformio.ini ​         # Configurarea proiectului 
 +└── .venv/ ​                 # Mediul virtual Python 
 +</​code>​ 
 + 
 +=== 3.6 Compilare și upload === 
 + 
 +<code bash> 
 +# Compilare 
 +pio run 
 + 
 +# Upload pe placă (asigurați-vă că aveți permisiuni pe portul serial) 
 +sudo chmod 666 /​dev/​ttyACM0 ​  # sau /​dev/​ttyUSB0,​ depinde de placă 
 +pio run -t upload 
 + 
 +# Monitor serial (pentru debug) 
 +pio device monitor -b 115200 
 +</​code>​ 
 + 
 +De asemenea, în Visual Studio Code (cu extensia PlatformIO) aceleași acțiuni se pot face și din tastatură:​ 
 + 
 +  * **''​Ctrl''​ + ''​Alt''​ + ''​B''​** – build (compilează proiectul) 
 +  * **''​Ctrl''​ + ''​Alt''​ + ''​U''​** – upload pe placă 
 + 
 +Astfel nu mai este necesar să rulați comenzile manual în terminal. 
 +===== Codul sursă ===== 
 + 
 +==== Firmware ESP32 (''​camera/​src/​main.cpp''​) ==== 
 + 
 +Acesta este codul care rulează pe cameră. Analizați-l cu atenție. 
 + 
 +<file cpp main.cpp>​ 
 +/​********************************************************************** 
 +  Filename ​   ​Camera MQTT Client 
 +  Description : ESP32-CAM MQTT Image Transfer 
 +**********************************************************************/​ 
 +#include "​esp_camera.h"​ 
 +#include <​WiFi.h>​ 
 +#include <​PubSubClient.h>​ 
 +// CAMERA_MODEL is defined in platformio.ini 
 +#include "​camera_pins.h"​ 
 + 
 +// =========================== 
 +// Configuration 
 +// =========================== 
 +const char* ssid     = ""; ​      // TODO: Modificați cu SSID-ul rețelei voastre 
 +const char* password = ""; ​    // TODO: Modificați cu parola rețelei voastre 
 +const char* mqtt_server = "​10.10.10.10";​ // TODO: Modificați cu IP-ul calculatorului (ip addr / ipconfig) 
 +const int mqtt_port = 1883; 
 + 
 +// Topics 
 +const char* TOPIC_COMMAND = "​ssproject/​commands";​ 
 +const char* TOPIC_IMAGE ​  = "​ssproject/​images";​ 
 + 
 +WiFiClient espClient;​ 
 +PubSubClient client(espClient);​ 
 + 
 +// State variables 
 +bool streaming = false; 
 +bool take_one_picture = false; 
 +unsigned long last_capture_time = 0; 
 +const unsigned long STREAM_INTERVAL = 100; // ms 
 + 
 +void setup_camera() { 
 +  camera_config_t config = {}; 
 +  config.ledc_channel ​   = LEDC_CHANNEL_0;​ 
 +  config.ledc_timer ​     = LEDC_TIMER_0;​ 
 +  config.pin_d0 ​         = Y2_GPIO_NUM;​ 
 +  config.pin_d1 ​         = Y3_GPIO_NUM;​ 
 +  config.pin_d2 ​         = Y4_GPIO_NUM;​ 
 +  config.pin_d3 ​         = Y5_GPIO_NUM;​ 
 +  config.pin_d4 ​         = Y6_GPIO_NUM;​ 
 +  config.pin_d5 ​         = Y7_GPIO_NUM;​ 
 +  config.pin_d6 ​         = Y8_GPIO_NUM;​ 
 +  config.pin_d7 ​         = Y9_GPIO_NUM;​ 
 +  config.pin_xclk ​       = XCLK_GPIO_NUM;​ 
 +  config.pin_pclk ​       = PCLK_GPIO_NUM;​ 
 +  config.pin_vsync ​      = VSYNC_GPIO_NUM;​ 
 +  config.pin_href ​       = HREF_GPIO_NUM;​ 
 +  config.pin_sccb_sda ​   = SIOD_GPIO_NUM;​ 
 +  config.pin_sccb_scl ​   = SIOC_GPIO_NUM;​ 
 +  config.pin_pwdn ​       = PWDN_GPIO_NUM;​ 
 +  config.pin_reset ​      = RESET_GPIO_NUM;​ 
 +  config.xclk_freq_hz ​   = 20000000; 
 +  config.pixel_format ​   = PIXFORMAT_JPEG;​ 
 +   
 +  if (psramFound()) { 
 +    Serial.println("​PSRAM found!"​);​ 
 +    config.frame_size ​   = FRAMESIZE_VGA;​ 
 +    config.jpeg_quality ​ = 12;  
 +    config.fb_count ​     = 2; 
 +  } else { 
 +    Serial.println("​No PSRAM foundusing DRAM"​);​ 
 +    ​config.frame_size ​   = FRAMESIZE_SVGA;​ 
 +    config.jpeg_quality ​ = 12;  
 +    config.fb_count ​     = 1; 
 +    config.fb_location ​  = CAMERA_FB_IN_DRAM;​ 
 +  } 
 +   
 +  Serial.println("​Initializing camera..."​);​ 
 +  esp_err_t err = esp_camera_init(&​config);​ 
 +  if (err != ESP_OK) { 
 +    Serial.printf("​Camera init failed with error 0x%x\n",​ err); 
 +    return; 
 +  } 
 +  Serial.println("​Camera Ready!"​);​ 
 +
 + 
 +void callback(chartopic, bytepayload, unsigned int length) { 
 +  Serial.println(">>>​ CALLBACK FIRED <<<"​);​ 
 +  String message; 
 +  for (int i = 0; i < length; i++) { 
 +    message += (char)payload[i];​ 
 +  } 
 +  Serial.printf("​Topic:​ %s\n", topic); 
 +  Serial.printf("​Message:​ [%s] (len=%u)\n",​ message.c_str(),​ length); 
 + 
 +  if (String(topic) == TOPIC_COMMAND) { 
 +    if (message == "​CAPTURE"​) { 
 +      take_one_picture = true; 
 +      Serial.println("​=>​ Action: take_one_picture = true"​);​ 
 +    } else if (message == "​START-LIVE"​) { 
 +      streaming = true; 
 +      Serial.println("​=>​ Action: Streaming Started"​);​ 
 +    } else if (message == "​STOP-LIVE"​) { 
 +      streaming = false; 
 +      Serial.println("​=>​ Action: Streaming Stopped"​);​ 
 +    } else { 
 +      Serial.println("​=>​ Unknown command, ignoring"​);​ 
 +    } 
 +  } else { 
 +    Serial.println("​=>​ Wrong topic, ignoring"​);​ 
 +  } 
 +
 + 
 +void reconnect() { 
 +  while (!client.connected()) { 
 +    Serial.print("​Attempting MQTT connection..."​);​ 
 +    String clientId = "​ESP32CamClient-";​ 
 +    clientId += String(random(0xffff),​ HEX); 
 +    Serial.printf("​ (clientId=%s)\n",​ clientId.c_str());​ 
 +     
 +    if (client.connect(clientId.c_str())) { 
 +      Serial.println("​MQTT connected!"​);​ 
 +      bool subOk = client.subscribe(TOPIC_COMMAND);​ 
 +      Serial.printf("​Subscribe to '​%s':​ %s\n", TOPIC_COMMAND,​ subOk ? "​OK"​ : "​FAILED"​);​ 
 +      Serial.printf("​Buffer size: %d\n", client.getBufferSize());​ 
 +      Serial.printf("​Free heap: %u bytes\n",​ ESP.getFreeHeap());​ 
 +    } else { 
 +      Serial.print("​failed,​ rc="​);​ 
 +      Serial.print(client.state());​ 
 +      Serial.println("​ try again in 5 seconds"​);​ 
 +      delay(5000);​ 
 +    } 
 +  } 
 +
 + 
 +void setup() { 
 +  Serial.begin(115200);​ 
 +  delay(1000);​ 
 +  Serial.println();​ 
 +  Serial.println("​============================"​);​ 
 +  Serial.println(" ​ ESP32-CAM MQTT Client"​);​ 
 +  Serial.println("​============================"​);​ 
 +  Serial.printf("​Free heap at start: %u bytes\n",​ ESP.getFreeHeap());​ 
 +  Serial.printf("​PSRAM size: %u bytes\n",​ ESP.getPsramSize());​ 
 + 
 +  setup_camera();​ 
 + 
 +  Serial.printf("​Connecting to WiFi: %s\n", ssid); 
 +  WiFi.begin(ssid,​ password);​ 
 +  while (WiFi.status() != WL_CONNECTED) { 
 +    delay(500);​ 
 +    Serial.print("​."​);​ 
 +  } 
 +  Serial.printf("​\nWiFi connected! IP: %s\n", WiFi.localIP().toString().c_str());​ 
 + 
 +  client.setServer(mqtt_server,​ mqtt_port);​ 
 +  client.setCallback(callback);​ 
 +  client.setBufferSize(65000);​  
 +
 + 
 +void captureAndPublish() { 
 +    camera_fb_t ​fb = esp_camera_fb_get();​ 
 +    if (!fb) { 
 +        Serial.println("​Camera capture failed"​);​ 
 +        return; 
 +    } 
 +     
 +    if (client.publish(TOPIC_IMAGE,​ (const uint8_t*)fb->​buf,​ fb->​len)) { 
 +        Serial.printf("​Image published: %u bytes\n",​ fb->​len);​ 
 +    } else { 
 +        Serial.println("​Publish failed"​);​ 
 +    } 
 +     
 +    esp_camera_fb_return(fb);​ 
 +
 + 
 +unsigned long last_heartbeat = 0; 
 + 
 +void loop() { 
 +  if (!client.connected()) { 
 +    Serial.println("​MQTT disconnected,​ reconnecting..."​);​ 
 +    reconnect();​ 
 +  } 
 +  client.loop();​ 
 + 
 +  unsigned long now = millis(); 
 + 
 +  // Print a heartbeat every 5 seconds so you know the loop is running 
 +  if (now - last_heartbeat > 5000) { 
 +    Serial.printf("​[heartbeat] millis=%lu connected=%d streaming=%d free_heap=%u\n",​ 
 +                  now, client.connected(),​ streaming, ESP.getFreeHeap());​ 
 +    last_heartbeat = now; 
 +  } 
 +   
 +  if (take_one_picture) { 
 +    Serial.println("​Taking single picture..."​);​ 
 +    captureAndPublish();​ 
 +    take_one_picture = false; 
 +  } 
 +   
 +  if (streaming && (now - last_capture_time > STREAM_INTERVAL)) { 
 +    captureAndPublish();​ 
 +    last_capture_time = now; 
 +  } 
 +
 +</​file>​ 
 + 
 +<note warning>​Nu deschideți ''​Serial Monitor''​ în Visual Studio Code, deoarece este foarte posibil să-și dea ''​RESET''​ placa.</​note>​ 
 + 
 +==== Receiver Python (''​receiver/​receiver.py''​) ==== 
 + 
 +Acesta este clientul care rulează pe calculator, primește imaginile și trimite comenzi. 
 + 
 +<file python receiver.py>​ 
 +import paho.mqtt.client as mqtt 
 +import cv2 
 +import numpy as np 
 +import threading 
 + 
 +# Configuration 
 +BROKER = "​192.168.50.239" ​ # TODO: Modificați cu IP-ul brokerului vostru 
 +PORT = 1883 
 +TOPIC_IMAGE = "​ssproject/​images"​ 
 +TOPIC_COMMAND = "​ssproject/​commands"​ 
 + 
 +# Global flags 
 +running = True 
 + 
 +# Shared frame storage (thread-safe via lock) 
 +latest_frame = None 
 +frame_lock = threading.Lock() 
 + 
 +def on_connect(client,​ userdata, flags, rc): 
 +    if rc == 0: 
 +        print("​Connected to MQTT Broker!"​) 
 +        client.subscribe(TOPIC_IMAGE) 
 +    else: 
 +        print(f"​Failed to connect, return code {rc}"​) 
 + 
 +def on_message(client,​ userdata, msg): 
 +    global latest_frame 
 +    try: 
 +        nparr = np.frombuffer(msg.payload,​ np.uint8) 
 +        img = cv2.imdecode(nparr,​ cv2.IMREAD_COLOR) 
 + 
 +        if img is not None: 
 +            # Store the frame — do NOT call cv2.imshow here (wrong thread!) 
 +            with frame_lock:​ 
 +                latest_frame = img 
 +        else: 
 +            print("​Failed to decode image"​) 
 +    except Exception as e: 
 +        print(f"​Error processing image: {e}"​) 
 + 
 +def main(): 
 +    global running, latest_frame 
 +    client = mqtt.Client() 
 +    client.on_connect = on_connect 
 +    client.on_message = on_message 
 + 
 +    try: 
 +        client.connect(BROKER,​ PORT, 60) 
 +        client.loop_start() 
 + 
 +        print("​\n--- ESP32 Camera Controller ---"​) 
 +        print("​Controls:"​) 
 +        print("​ '​s'​ : Take Single Picture"​) 
 +        print("​ '​b'​ : Begin Stream"​) 
 +        print("​ '​e'​ : End Stream"​) 
 +        print("​ '​q'​ : Quit"​) 
 +        print("​-------------------------------\n"​) 
 + 
 +        cv2.namedWindow("​ESP32-CAM Stream",​ cv2.WINDOW_AUTOSIZE) 
 + 
 +        while running: 
 +            # Display the latest frame if available (main thread only) 
 +            with frame_lock:​ 
 +                frame = latest_frame 
 + 
 +            if frame is not None: 
 +                cv2.imshow("​ESP32-CAM Stream",​ frame) 
 + 
 +            # Handle GUI events and keyboard input (main thread only) 
 +            key = cv2.waitKey(30) & 0xFF 
 + 
 +            if key == ord('​q'​):​ 
 +                running = False 
 +            elif key == ord('​s'​):​ 
 +                print("​Command:​ Capture"​) 
 +                client.publish(TOPIC_COMMAND,​ "​CAPTURE"​) 
 +            elif key == ord('​b'​):​ 
 +                print("​Command:​ Start Stream"​) 
 +                client.publish(TOPIC_COMMAND,​ "​START-LIVE"​) 
 +            elif key == ord('​e'​):​ 
 +                print("​Command:​ Stop Stream"​) 
 +                client.publish(TOPIC_COMMAND,​ "​STOP-LIVE"​) 
 + 
 +    except KeyboardInterrupt:​ 
 +        print("​\nExiting..."​) 
 +    except Exception as e: 
 +        print(f"​Error:​ {e}"​) 
 +    finally: 
 +        client.loop_stop() 
 +        client.disconnect() 
 +        cv2.destroyAllWindows() 
 + 
 +if __name__ == "​__main__":​ 
 +    main() 
 +</​file>​ 
 + 
 +===== Structura codului ===== 
 + 
 +==== Firmware (''​main.cpp''​) ==== 
 + 
 +Codul de pe cameră îndeplinește următoarele funcții: 
 + 
 +  * **''​setup_camera()''​**: Inițializează senzorul OV2640. 
 +  * **''​callback()''​**:​ Funcția apelată când se primește un mesaj pe ''​ssproject/commands''​. Interpretează:​ 
 +    * ''​CAPTURE''​ -> Face o poză. 
 +    * ''​START-LIVE''​ -> Activează flag-ul ''​streaming''​. 
 +    * ''​STOP-LIVE''​ -> Dezactivează flag-ul ''​streaming''​. 
 +  * **''​loop()''​**:​ Verifică starea ''​streaming''​. Dacă este activ, capturează și trimite o imagine la fiecare 100ms. 
 + 
 +==== Configurare Wi-Fi și MQTT ==== 
 + 
 +În ''​main.cpp'',​ trebuie să modificați următoarele constante pentru a corespunde rețelei voastre: 
 + 
 +<code cpp> 
 +const char* ssid     = "​NUME_RETEA";​ 
 +const char* password = "​PAROLA_RETEA";​ 
 +const char* mqtt_server = "​IP_CALCULATOR";​ // Rulați `ip addr` sau `ipconfig` pentru a-l afla 
 +</​code>​
  
-===== Funcționalități =====+==== Receiver (''​receiver.py''​) ​====
  
-==== 1. Construirea ​și gestionarea containerelor Docker ==== +Scriptul Python se conectează la broker ​și afișează imaginile folosind OpenCV. De asemeneaascultă tastatura ​pentru ​a trimite comenzi:
-  * Crearea unui Dockerfile pentru aplicație +
-  * Configurarea unui sistem de build și push automat către un registry (Docker HubGitHub Container Registry) +
-  * Utilizarea Docker Compose ​pentru ​rularea serviciilor local+
  
-==== 2. Implementarea pipeline-ului CI/CD ==== +  * **''​b''​**:​ Begin Stream (''​START-LIVE''​) 
-  * Definirea workflow-ului CI/CD (build, push, deploy+  * **''​e''​**:​ End Stream ​(''​STOP-LIVE''​
-  * Configurarea unui sistem de build automat la fiecare commit sau pull request +  * **''​s''​**:​ Single Capture (''​CAPTURE''​) 
-  * Automatizarea livrării containerului către registry+  * **''​q''​**:​ Quit
  
-==== 3. Deployment automatizat ​==== +===== Desfășurarea laboratorului =====
-  * Implementarea unui sistem de deploy automat în mediu de testare +
-  * Configurarea unui mediu de staging/​producție folosind Kubernetes/​Docker Swarm +
-  * Rollback automat în caz de eșec al deployment-ului+
  
-===== Evaluare ===== +  - **Configurare rețea**: Deschideți ''​camera/​src/​main.cpp'' ​și setați ''​ssid'',​ ''​password''​ și ''​mqtt_server'' ​(IP-ul PC-ului vostru). 
-  ​Construirea ​și livrarea aplicației în containere Docker ​(40%+  ​**Pornire broker**: Rulațcomanda de pornire Mosquitto într-un terminal. 
-  * Configurarea șrularea pipeline-ului CI/CD (30%) +  ​**Pornire receiver**: Rulați ''​python receiver.py''​ într-un alt terminal. 
-  * Deployment automatizat în mediu de test/producție (30%)+  - **Upload**:​ 
 +    * Conectați ESP32-CAM la USB (prin programator,​ dacă e cazul)
 +    * Asigurați-vă că aveți permisiuni pe portul serial: ''​sudo chmod 666 /​dev/​ttyACM0''​. 
 +    * Folosiți comanda ''​Upload''​ din PlatformIO sau terminal: ''​pio run -t upload''​. 
 +  - **Testare**:​ 
 +    * După resetare, camera se va conecta la Wi-Fi. 
 +    * Din fereastra receiver-ului,​ apăsați ''​b''​ pentru a porni live stream-ul. 
 +    * Verificați latența și calitatea imaginii.
  
-===== Resurse suplimentare ===== +<note tip> 
-  * [https://​docs.github.com/​en/​actions GitHub Actions Documentation] / [https://​docs.gitlab.com/​ee/​ci GitLab CI/CD Documentation] +Dacă ați configurat totul corect (broker-ul este pornit, camera publică pe ''​ssproject/images'',​ și receiver-ul sau aplicația web este conectată la același broker), ar trebui să puteți vizualiza stream-ul și prin intermediul ​**interfaței web** a aplicației (serverul web care face subscribe la același topic MQTT)Aceasta confirmă faptul că sistemul funcționează end-to-end
-  ​[https://​www.docker.com Docker Documentation] +</note>
-  * [https://​kubernetes.io/docs Kubernetes Documentation]+
  
 +===== Întrebări și exerciții =====
  
 +  - Ce se întâmplă dacă modificați ''​STREAM_INTERVAL''​ în ''​main.cpp''​ la o valoare mai mică (ex: 20ms)? Cum afectează asta calitatea imaginii și latența?
 +  - Analizați funcția ''​callback''​ din ''​main.cpp''​. Adăugați o comandă nouă ''​FLASH-ON''​ care să aprindă LED-ul flash al camerei (GPIO 4).
ss/laboratoare/03.1740514898.txt.gz · Last modified: 2025/02/25 22:21 by jan.vaduva
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0