Refactor code structure for improved readability and maintainability

This commit is contained in:
2025-04-28 00:52:40 +02:00
parent b6e0080caa
commit 93026436a9
48 changed files with 2116 additions and 126 deletions

View File

@@ -0,0 +1,56 @@
@startuml architecture_timelapse
' Configuration pour rendre le diagramme plus compact
skinparam padding 1
skinparam nodesep 5
skinparam ranksep 1
skinparam componentMargin 1
skinparam packagePadding 2
skinparam defaultTextAlignment center
skinparam linetype ortho
skinparam rectangle {
borderColor transparent
stereotypeBorderColor transparent
}
!$ICONURL = "https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/v3.0.0/icons"
!include $ICONURL/common.puml
!include $ICONURL/devicons/javascript.puml
!include $ICONURL/devicons/html5.puml
!include $ICONURL/devicons/css3.puml
!include $ICONURL/devicons/nodejs.puml
!include $ICONURL/devicons/postgresql.puml
package "Hôte Proxmox" {
package "Conteneur LXC" as lxc {
package "Frontend" as frontend {
DEV_HTML5(html, "HTML5")
DEV_CSS3(css, "CSS3") #line:transparent
DEV_JAVASCRIPT(js, "JavaScript") #line:transparent
}
package "Backend" as backend {
DEV_NODEJS(express, "ExpressJS") #line:transparent
[FFmpeg] as ffmpeg #line:transparent
note right of ffmpeg: Image vers Vidéo
}
database "Base de données" as db {
DEV_POSTGRESQL(pg, "PostgreSQL") #line:transparent
note right of pg: Timelapses & Données
}
frontend --> backend : HTTP/REST
backend --> db : Requêtes
backend --> ffmpeg : Traitement
}
storage "Réplication Ceph" as ceph {
[Stockage de données] as storage #line:transparent
note right of storage: Stockage distribué
}
lxc --> ceph : Stockage
}
@enduml

View File

@@ -0,0 +1,77 @@
@startuml Modèles de données
class Project {
+id: integer
+name: string
+description: string
+start_date: date
+status: integer
+getAllProjects()
+getProjectById(id)
+createProject(name, description, startDate, status)
+updateProject(id, updates)
+updateProjectStatus(id, status)
+deleteProject(id)
+findCurrentRenderingProject()
+findStoppingProject()
}
class Measurement {
+id: integer
+project_id: integer
+timestamp: datetime
+path: string
+temperature: float
+humidity: float
+order_id: integer
+getAllMeasurements()
+getMeasurementById(id)
+getMeasurementByProjectAndOrderId(projectId, orderId)
+getMeasurementsByProjectId(projectId)
+createMeasurement(projectId, timestamp, path, temperature, humidity, orderId)
+updateMeasurement(id, updates)
+deleteMeasurement(id)
+getNextOrderId(projectId)
}
class Video {
+id: integer
+project_id: integer
+measurement_ids: string
+name: string
+resolution: string
+duration: integer
+status: integer
+progress: float
+video_file: string
+started_at: datetime
+updated_at: datetime
+eta: float
+getAllVideos()
+getVideoById(id)
+getVideosByProjectId(projectId)
+createVideo(projectId, measurementIds, name, resolution, duration, status)
+updateVideo(id, updates)
+updateVideoFilePath(id, videoFile)
+updateVideoStatus(id, status)
+deleteVideo(id)
+getUnfinishedVideos()
+updateVideoProgress(id, progress, eta)
}
class Camera {
+id: integer
+interval: integer
+maintenance: integer
+active: integer
+getCamera()
+updateCamera(id, updates)
+deleteCamera(id)
+initializeCamera()
}
Project "1" -- "0..*" Measurement : possède >
Project "1" -- "0..*" Video : possède >
Measurement "1..*" -- "0..*" Video : utilisée dans >
@enduml

View File

@@ -0,0 +1,62 @@
@startuml Architecture MVC
package "Controllers" {
[ProjectController]
[MeasurementController]
[VideoController]
[ImageController]
[CameraController]
}
package "Models" {
[Project]
[Measurement]
[Video]
[Camera]
[DatabaseManager]
}
package "Routes" {
[projectRoutes]
[measurementRoutes]
[videoRoutes]
[imageRoutes]
[cameraRoutes]
[index]
}
package "Services" {
[StorageService]
[VideoService]
}
package "Utils" {
[errorHandler]
}
package "Database" {
[connection]
}
package "Config" {
[config]
}
cloud "Client" {
[Frontend]
}
[Frontend] --> [Routes]
[Routes] --> [Controllers]
[Controllers] --> [Models]
[Controllers] --> [Services]
[Models] --> [Database]
[Services] --> [Models]
[Controllers] --> [Utils]
[Models] --> [Utils]
[Services] --> [Utils]
[Models] --> [Config]
[Services] --> [Config]
[Controllers] --> [Config]
@enduml

View File

@@ -0,0 +1,39 @@
@startuml Création de vidéo
actor Client
participant "videoRoutes" as Routes
participant "VideoController" as Controller
participant "Video" as Model
participant "Measurement" as MeasurementModel
participant "VideoService" as Service
participant "FFmpeg" as FFmpeg
database Database
Client -> Routes: POST /videos
Routes -> Controller: createVideo(req, res)
Controller -> Model: createVideo(project_id, measurement_ids, name, resolution, duration)
Model -> Database: INSERT INTO videos
Database --> Model: video data
Model --> Controller: video object
Controller -> Controller: getMeasurementPathList(measurement_ids, project_id)
Controller -> MeasurementModel: getMeasurementByProjectAndOrderId(projectId, orderId)
MeasurementModel -> Database: SELECT * FROM measurements
Database --> MeasurementModel: measurement data
MeasurementModel --> Controller: measurement object with path
Controller -> Service: createVideoFromImages(project_id, pathList, duration, video_id, resWidth, resHeight)
Service -> FFmpeg: spawn('ffmpeg', ffmpegArgs)
Service -> Model: updateVideo(videoId, {status: rendering, progress: 0})
Model -> Database: UPDATE videos SET status = rendering, progress = 0
FFmpeg --> Service: stderr progress events
Service -> Model: updateVideoProgress(videoId, progress, eta)
Model -> Database: UPDATE videos SET progress = X, eta = Y
FFmpeg --> Service: process complete
Service -> Model: updateVideo(videoId, {status: completed, progress: 100})
Model -> Database: UPDATE videos SET status = completed, progress = 100
Service --> Controller: videoFile path
Controller --> Routes: { message: success, id: video.id }
Routes --> Client: 200 OK - JSON Response
@enduml

View File

@@ -0,0 +1,34 @@
@startuml Cas d'utilisation
left to right direction
actor "Utilisateur" as User
actor "Caméra" as Camera
rectangle "Timelapse Backend" {
usecase "Gérer les projets" as UC1
usecase "Configurer la caméra" as UC2
usecase "Capturer des images" as UC3
usecase "Créer des vidéos" as UC4
usecase "Visualiser les images" as UC5
usecase "Visualiser les vidéos" as UC6
usecase "Démarrer une capture" as UC7
usecase "Arrêter une capture" as UC8
usecase "Uploader une image et des mesures" as UC9
UC1 ..> UC7 : <<include>>
UC1 ..> UC8 : <<include>>
UC2 ..> UC7 : <<extend>>
UC2 ..> UC8 : <<extend>>
UC3 ..> UC9 : <<include>>
UC4 ..> UC5 : <<include>>
}
User --> UC1
User --> UC2
User --> UC4
User --> UC5
User --> UC6
Camera --> UC3
Camera --> UC9
@enduml

View File

@@ -0,0 +1,41 @@
@startuml Déploiement
node "Client Device" {
[Web Browser] as Browser
}
node "Docker Environment" {
node "timelapse-api" {
[Express Server] as Server
[Node.js Runtime] as Node
[FFmpeg] as FFmpeg
}
database "timelapse-db" {
[PostgreSQL] as DB
}
folder "Volumes" {
folder "storage/" {
[Project Images]
[Generated Videos]
}
}
}
node "Camera Device" {
[Camera Software] as CamSoftware
[Sensors] as Sensors
}
Browser --> Server: HTTP/REST
CamSoftware --> Server: HTTP/REST
Server --> DB: SQL Queries
Server --> FFmpeg: Process Spawn
FFmpeg --> [Project Images]: Read
FFmpeg --> [Generated Videos]: Write
Server --> [Project Images]: Read/Write
Server --> [Generated Videos]: Read
Sensors --> CamSoftware: Temperature/\nHumidity Data
@enduml

View File

@@ -0,0 +1,42 @@
@startuml
class Project {
id: number
name: string
description: string
status: number
start_date: date
}
class Measurement {
id: number
project_id: number
order_id: number
timestamp: string
temperature: number
humidity: number
}
class Video {
id: number
project_id: number
name: string
measurement_ids: string
resolution: string
duration: number
status: number
}
class CameraController {
active_project_id: number
start_timelapse(id, frequency, nbimages): void
stopCamera(id): void
manualUpload(imageFile, projectId, timestamp, temperature, humidity): void
}
Project "1" *-- "n" Measurement : contient
Project "1" *-- "n" Video : contient
Measurement "n" o-- "n" Video : utilisées dans
CameraController -- Video : génère
@enduml

View File

@@ -0,0 +1,19 @@
@startuml
start
:Créer un projet;
:Configurer la caméra;
:Prises d'images automatiques;
fork
:Upload manuel d'images;
fork again
:Arrêt de la caméra;
end fork
:Sélection des images;
:Générer une vidéo;
:Visualiser les données;
stop
@enduml

View File

@@ -0,0 +1,20 @@
@startuml
actor Browser
participant Frontend
participant API
participant Camera
Browser -> Frontend : 1. Create project
Frontend -> API : 2. POST /projects
Browser -> Frontend : 3. Configure camera
Frontend -> API : 4. POST /procedure/start
API -> Camera : 4. Start capturing
Camera --> API : 5. Capture images
Browser -> Frontend : 6. Create video request
Frontend -> API : 7. POST /videos
Browser -> Frontend : 8. Render video
Frontend -> API : 9. POST /videos/render/{id}
Frontend --> Browser : 10. Display video & metrics
@enduml

View File

@@ -0,0 +1,28 @@
@startuml
left to right direction
actor "Utilisateur" as user
rectangle "Système Timelapse" {
usecase "Gérer les projets" as UC1
usecase "Configurer la caméra" as UC2
usecase "Créer des vidéos" as UC3
usecase "Visualiser les données" as UC4
usecase "Uploader manuellement" as UC5
usecase "Afficher métriques" as UC6
UC1 --> UC2
UC2 --> UC3
UC1 --> UC4
UC2 --> UC5
UC3 --> UC6
}
user --> UC1
user --> UC2
user --> UC3
user --> UC4
user --> UC5
user --> UC6
@enduml

View File

@@ -0,0 +1,29 @@
@startuml
node "Client Browser" {
[HTML/CSS/JS]
[JQuery]
[Chart.js]
}
node "Backend API" {
[RESTful Services]
[Image Processing]
[Video Generation]
}
database "Filesystem Storage" {
[Images]
[Videos]
}
node "Camera Controller" {
[Capture Configuration]
[Sensors (temp/humid)]
}
[HTML/CSS/JS] -- [RESTful Services] : HTTP
[RESTful Services] -- [Filesystem Storage]
[RESTful Services] -- [Camera Controller]
@enduml

View File

@@ -1,4 +1,4 @@
@startuml Architecture Globale
@startuml global
' Définition des composants
node "Interfaces utilisateur" {

View File

@@ -0,0 +1,100 @@
@startuml
left to right direction
skinparam component {
BackgroundColor<<Informatique>> #FFE4B5
BackgroundColor<<Électronique>> #98FB98
BackgroundColor<<Matériaux>> #87CEEB
BorderColor #333
}
package "Infrastructure Globale" {
component "Caméra Raspberry Pi" <<Électronique>> as pi {
component "Module Caméra" as cam
component "Scripts Capture" as scripts
}
component "Serveur Central" <<Informatique>> as server {
component "Backend (Node.js/Express)" as backend
component "FFMPEG Processing" as ffmpeg
component "Base de Données" as db
}
component "Interface Web" <<Informatique>> as web {
component "Frontend (HTML/CSS/JS)" as front
component "Nginx Reverse Proxy" as nginx
}
component "Application Android" <<Informatique>> as android {
component "Kotlin API" as kotlin
component "Glide Image Processing" as glide
}
component "Système Énergétique" <<Électronique>> as energy {
component "Microcontrôleur STM32" as stm
component "Batterie LiPo" as battery
component "Panneau Solaire" as solar
}
component "Boîtier Mécanique" <<Matériaux>> as box {
component "Structure Étanche" as structure
component "Système Fixation" as mount
}
component "Infrastructure Virtualisée" <<Informatique>> as infra {
component "Proxmox VE" as proxmox
component "VM Ubuntu" as vm
component "Docker Containers" as docker
}
}
pi --> server : "Transfert images\n(HTTP/MQTT)"
server --> web : "API REST"
server --> android : "API REST"
energy --> pi : "Alimentation\n(Power Management)"
energy --> stm : "Contrôle énergie"
box --> pi : "Protection physique"
box --> energy : "Intégration"
infra --> server : "Hébergement"
infra --> web : "Hébergement"
cam --> scripts : "Capture RAW"
scripts --> backend : "Envoi images"
backend --> ffmpeg : "Conversion vidéo"
ffmpeg --> db : "Stockage"
stm --> battery : "Monitoring"
solar --> battery : "Recharge"
front --> nginx : "Requêtes"
nginx --> backend : "Proxy"
vm --> docker : "Orchestration"
structure --> mount : "Assemblage"
note top of pi
**Technologies Électronique**
- Altium Designer
- STM32 CubeIDE
- Protocoles I2C/SPI
end note
note right of server
**Stack Logicielle**
- Node.js + Express
- PostgreSQL
- FFMPEG
- CI/CD Gitea
end note
note left of energy
**Gestion Énergie**
- PCB Custom
- Capteurs température/hygro
- Algorithme économie d'énergie
end note
note bottom of box
**Caractéristiques Mécaniques**
- PLA résistant aux UV
- Indice IP67
- Dissipation thermique
end note
@enduml

View File

@@ -0,0 +1,87 @@
@startuml
left to right direction
skinparam component {
BackgroundColor<<Logiciel>> #FFE4B5
BackgroundColor<<Matériel>> #98FB98
BackgroundColor<<Infrastructure>> #87CEEB
BorderColor #333
}
package "Matériel" <<Matériel>> {
component "RPi 4B + Cam" as pi {
[Module Caméra] --> [Scripts Python]
}
component "Système d'énergie" as energy {
[STM32] --> [Batterie LiPo]
[Panneau Solaire] --> [Gestion d'énergie]
}
component "Boîtier Mécanique" as box {
[PLA IP67] --> [Système de Montage]
}
}
package "Logiciel" <<Logiciel>> {
component "Backend" as backend {
[Node.js] --> [FFMPEG]
[Express] --> [PostgreSQL]
}
component "Frontend" as web {
[React] --> [Nginx]
}
component "Application Mobile" as mobile {
[Kotlin] --> [Android API]
}
}
package "Infrastructure" <<Infrastructure>> {
component "Proxmox" as proxmox {
[VM Ubuntu] --> [Docker]
}
}
pi --> backend : "HTTP/MQTT\n(images)"
energy --> pi : "Alimentation"
box --> pi : "Protection physique"
backend --> web : "API REST"
backend --> mobile : "API REST"
proxmox --> backend : "Hébergement"
proxmox --> web : "Proxy inverse"
note right of pi
<b>Technologie Matérielle:</b>
• Altium Designer
• STM32 CubeIDE
• I2C/SPI
• RDM6/CES
end note
note bottom of backend
<b>Stack Logicielle:</b>
• Node.js/Express
• FFMPEG
• Auth JWT
• CI/CD Gitea
end note
note left of proxmox
<b>Infrastructure:</b>
• Docker Swarm
• Let's Encrypt
• VPN/Wireguard
• Sauvegardes Automatisées
end note
note top of box
<b>Mécanique:</b>
• Solidworks
• BambuLab X1
• Analyse Thermique
• Classification IP67
end note
@enduml

View File

@@ -0,0 +1,52 @@
@startuml Architecture Générale du Système Timelapse
!define ICONURL https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/v2.4.0
!include ICONURL/common.puml
!include ICONURL/devicons/python.puml
!include ICONURL/font-awesome-5/raspberry_pi.puml
!include ICONURL/font-awesome-5/cloud.puml
!include ICONURL/font-awesome-5/camera.puml
!include ICONURL/font-awesome-5/database.puml
skinparam {
BackgroundColor white
ArrowColor #666666
BorderColor #666666
FontName "Arial"
}
rectangle "Système Raspberry Pi" as raspi {
DEV_PYTHON(pyonline, "timelapse_online.py") #lightblue
DEV_PYTHON(pyoffline, "timelapse_offline.py") #lightgreen
rectangle "timelapse/" {
DEV_PYTHON(config, "config.py") #lightyellow
DEV_PYTHON(apiclient, "api_client.py") #pink
DEV_PYTHON(capture, "capture.py") #lightcyan
DEV_PYTHON(sensors, "sensors.py") #lightyellow
}
FA5_DATABASE(localdb, "CONFIG/config.json") #lightgrey
FA5_CAMERA(camera, "Caméra") #white
}
cloud "Serveur Distant" {
rectangle "API REST" as api #pink
database "Base de données" as db #lightgrey
}
pyonline --> config : utilise
pyoffline --> config : utilise
pyonline --> apiclient : utilise
pyonline --> capture : utilise
pyoffline --> capture : utilise
capture --> config : lit/écrit
capture --> sensors : utilise
apiclient --> api : communique
config --> localdb : lit/écrit
sensors --> camera : contrôle
note bottom of pyonline : "Mode connecté"
note bottom of pyoffline : "Mode hors ligne"
note right of api : "Authentification\net gestion des données"
note bottom of camera : "Capture des images"
@enduml

View File

@@ -0,0 +1,77 @@
@startuml Flux du Processus de Capture d'Images
skinparam {
BackgroundColor white
ArrowColor #666666
BorderColor #666666
FontName "Arial"
}
start
if (Connexion internet disponible?) then (oui)
:Mode connecté (timelapse_online.py);
:Récupération du statut depuis l'API;
if (Serveur accessible?) then (oui)
:Mise à jour de la configuration locale;
if (Mode maintenance?) then (oui)
:Arrêt du processus;
stop
else (non)
if (Demande d'arrêt?) then (oui)
:Confirmation de l'arrêt au serveur;
:Réinitialisation de la configuration;
stop
else (non)
if (Configuration active?) then (oui)
:Capture d'image;
:Lecture des données environnementales;
:Envoi au serveur;
if (Envoi réussi?) then (oui)
:Décrémenter le nombre d'images restantes;
else (non)
:Sauvegarder en mode hors-ligne;
endif
if (Toutes images capturées?) then (oui)
:Notification au serveur;
:Désactivation de la configuration;
stop
else (non)
:Attente du prochain cycle;
endif
else (non)
:Mode IDLE, aucune action;
stop
endif
endif
endif
else (non)
:Fonctionnement en mode dégradé;
endif
else (non)
:Mode hors ligne (timelapse_offline.py);
if (Configuration active?) then (oui)
if (Images restantes > 0?) then (oui)
:Capture d'image;
:Lecture des données environnementales;
:Sauvegarde en local;
:Décrémenter le nombre d'images restantes;
if (Toutes images capturées?) then (oui)
:Désactivation de la configuration;
stop
else (non)
:Envoi de l'intervalle au microcontrôleur;
:Attente du prochain cycle;
endif
else (non)
:Désactivation de la configuration;
stop
endif
else (non)
:Aucune configuration active;
stop
endif
endif
stop
@enduml

View File

@@ -0,0 +1,91 @@
@startuml Structure des Classes et Composants
skinparam {
BackgroundColor white
ClassBackgroundColor lightcyan
ClassBorderColor gray
ClassFontName Arial
ClassFontSize 12
}
class Config {
+ BASE_DIR : string
+ CONFIG_DIR : string
+ PROJECT_DIR : string
+ LOG_FILE : string
+ CONFIG_FILE : string
+ API_BASE_URL : string
+ API_ENDPOINTS : dict
+ DEFAULT_CONFIG : dict
--
+ ensure_directories()
+ setup_logging()
+ load_config()
+ save_config()
+ update_config(new_config)
+ get(key, default)
+ set(key, value)
+ delete_config_file()
+ decrement_remaining_images()
}
class APIClient {
- base_url : string
- headers : dict
--
+ get_camera_status()
+ upload_measurement(image_path, timestamp, temperature, humidity)
+ confirm_stop()
+ update_camera_config(status)
+ check_connection()
}
class TimelapseCaptureManager {
- offline_dir : string
--
+ single_capture(online)
+ run_capture_sequence(online)
+ sync_offline_captures()
+ count_offline_captures()
- _move_to_offline(image_path, json_path)
- _cleanup_local_capture(image_path, json_path)
}
class "timelapse_online.py" as TimelapseOnline {
+ main()
}
class "timelapse_offline.py" as TimelapseOffline {
+ main()
}
package "sensors" {
class EnvironmentalSensor {
+ read_data()
}
class Camera {
+ capture_image()
}
class MicroController {
+ send_interval(interval)
}
}
Config "1" <-- "1" TimelapseOnline : utilise
Config "1" <-- "1" TimelapseOffline : utilise
Config "1" <-- "1" TimelapseCaptureManager : utilise
APIClient "1" <-- "1" TimelapseOnline : utilise
TimelapseCaptureManager "1" <-- "1" TimelapseOnline : utilise
TimelapseCaptureManager "1" <-- "1" TimelapseOffline : utilise
TimelapseCaptureManager "1" --> "1" EnvironmentalSensor : utilise
TimelapseCaptureManager "1" --> "1" Camera : utilise
APIClient "1" --> "1" Config : utilise
TimelapseOffline ..> MicroController : utilise
note bottom of Config : "Gestion de la configuration\nlocale et persistance"
note bottom of APIClient : "Communication avec\nle serveur distant"
note bottom of TimelapseCaptureManager : "Orchestration du processus\nde capture d'images"
@enduml

View File

@@ -0,0 +1,78 @@
@startuml Séquence de Synchronisation des Données
skinparam {
BackgroundColor white
SequenceGroupBorderColor gray
SequenceGroupBodyBackgroundColor whitesmoke
ParticipantBackgroundColor lightblue
ParticipantBorderColor gray
LifeLineBorderColor gray
ArrowColor #666666
}
actor "Système" as System
participant "sync_offline_data.py" as Sync
participant "APIClient" as API
participant "TimelapseCaptureManager" as Manager
participant "Config" as Config
database "Stockage local" as Storage
database "Serveur API" as Server
System -> Sync : Exécution du script
activate Sync
Sync -> API : check_connection()
activate API
API --> Sync : Connexion disponible
deactivate API
Sync -> Manager : count_offline_captures()
activate Manager
Manager -> Storage : Listing des dossiers offline
Storage --> Manager : Liste des captures
Manager --> Sync : Nombre de captures hors ligne
deactivate Manager
alt Captures hors ligne disponibles
Sync -> Manager : sync_offline_captures()
activate Manager
loop Pour chaque capture hors ligne
Manager -> Storage : Lire données JSON
activate Storage
Storage --> Manager : Données (timestamp, température, etc.)
deactivate Storage
Manager -> Storage : Lire image
activate Storage
Storage --> Manager : Fichier image
deactivate Storage
Manager -> API : upload_measurement()
activate API
API -> Server : POST /camera/upload
alt Upload réussi
Server --> API : Confirmation (ID image)
API --> Manager : Succès
Manager -> Storage : Suppression des fichiers locaux
Manager -> Config : Mise à jour du statut
else Échec de l'upload
Server --> API : Erreur
API --> Manager : Échec
note right: Conservation des fichiers locaux\npour tentative ultérieure
end
deactivate API
end
Manager --> Sync : Nombre de captures synchronisées
deactivate Manager
else Aucune capture à synchroniser
Sync -> Sync : Fin sans action
end
Sync --> System : Rapport de synchronisation
deactivate Sync
@enduml

View File

@@ -0,0 +1,69 @@
@startuml infra_raspi
skinparam {
BackgroundColor white
NodeBackgroundColor lightyellow
NodeBorderColor gray
AgentBackgroundColor lightcyan
AgentBorderColor gray
ArrowColor #666666
ComponentBackgroundColor lightblue
ComponentBorderColor gray
}
artifact "Raspbian OS" as linux
node "Raspberry Pi" as raspi {
agent "Service Systemd" as service
artifact "timelapse.service" as timelapseService
artifact "script.sh" as script
service --> timelapseService : gère
service --> script : exécute
component "Scripts Python" as scripts {
artifact "timelapse_online.py" as pyOnline
artifact "timelapse_offline.py" as pyOffline
artifact "sync_offline_data.py" as pySync
}
component "Modules Timelapse" as modules {
artifact "config.py" as config
artifact "api_client.py" as apiClient
artifact "capture.py" as capture
artifact "sensors.py" as sensors
}
artifact "Caméra Pi" as cam
artifact "Microcontrôleur" as micro
}
cloud "Internet" as internet {
node "Serveur API" as api_server {
database "Base de données" as db
folder "Stockage d'images" as images
}
}
linux --> service : exécute
service --> script : lance
script --> scripts : appelle selon\nétat connexion
scripts --> modules : utilisent
modules --> cam : contrôle
modules --> micro : communique
modules --> internet : envoie données
internet --> modules : récupère configuration
note right of service : "Démarrage au boot\net exécution périodique"
note right of scripts : "Sélection auto du mode\nselon connectivité"
note bottom of cam : "Capture des images\ndu timelapse"
note bottom of micro : "Gestion de l'intervalle\nde capture"
legend right
<b>Infrastructure de Déploiement Timelapse</b>
Ce diagramme représente l'infrastructure complète
du système timelapse, depuis le service systemd
jusqu'à la communication avec le serveur distant.
endlegend
@enduml