Skip to content

πŸ”¬ Lab Expert is a lab experiment visualization app that helps students and researchers understand complex experimental setups through interactive simulations. It bridges theory and practice by providing clear, engaging visuals for lab procedures, making it a valuable tool for education and research.

Notifications You must be signed in to change notification settings

shavihara/LabExpert

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

271 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”¬ LabExpert

An IoT-powered laboratory experiment platform for physics education

React FastAPI ESP32 MQTT SQLite Vite PWA MIT License


πŸ“– Overview

LabExpert is a full-stack IoT platform that connects ESP32 sensor modules to a React web application through a Python backend, enabling real-time physics experiments in educational labs. Students and educators can select experiments, wirelessly connect to sensor hardware, collect live data, and visualize results β€” all from a browser.

✨ Key Features

  • πŸ”¬ 5 Experiment Categories β€” Distance, Oscillation, Temperature, Light Intensity, and AI-powered Motion Analysis
  • πŸ“‘ Real-Time Data Streaming β€” MQTT-based sensor data with binary packet optimization
  • πŸ“Š Live Graphing β€” Interactive Plotly.js charts with multi-axis visualization
  • πŸ”„ Over-the-Air Updates β€” Dual-partition OTA firmware deployment to ESP32 modules
  • πŸ“² BLE Provisioning β€” Zero-config WiFi setup for sensor modules via Bluetooth
  • πŸ” UDP Auto-Discovery β€” Automatic detection of sensor modules on the local network
  • πŸ‘₯ Multi-User Support β€” Per-device session management with conflict prevention
  • πŸ›‘οΈ Admin Dashboard β€” User management, device monitoring, and system control
  • πŸ“± PWA Support β€” Installable as a native-like app on mobile and desktop
  • πŸŒ™ Dark Mode β€” Full dark theme support across the application

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          React Frontend (PWA)                         β”‚
β”‚         Vite 6 Β· React 19 Β· TailwindCSS Β· Plotly.js Β· Zustand         β”‚
β”‚                                                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Auth &   β”‚ β”‚   User       β”‚ β”‚ Experimentβ”‚ β”‚  Admin Dashboard     β”‚ β”‚
β”‚  β”‚  Signup   β”‚ β”‚  Dashboard   β”‚ β”‚ Interface β”‚ β”‚  & Management        β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚        β”‚              β”‚              β”‚                β”‚                β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
β”‚                       WebSocket + REST API                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
                                β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Python Backend (FastAPI)                          β”‚
β”‚          Uvicorn Β· SQLAlchemy Β· paho-mqtt Β· Mosquitto Broker           β”‚
β”‚                                                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Session &   β”‚ β”‚   MQTT     β”‚ β”‚    OTA     β”‚ β”‚  Sensor Processor β”‚ β”‚
β”‚  β”‚  Device Mgr  β”‚ β”‚  Service   β”‚ β”‚  Manager   β”‚ β”‚    Pipeline       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  User Auth   β”‚ β”‚    UDP     β”‚ β”‚    BLE     β”‚ β”‚  WebSocket Client β”‚ β”‚
β”‚  β”‚  & Admin     β”‚ β”‚  Discovery β”‚ β”‚  Service   β”‚ β”‚    Manager        β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚ MQTT (1883)       β”‚ UDP (8888/8889)    β”‚ HTTP OTA
            β–Ό                   β–Ό                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        ESP32 Sensor Modules                            β”‚
β”‚                                                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  OTA Bootloader     β”‚      β”‚  Experiment Firmware               β”‚   β”‚
β”‚  β”‚  (Partition ota_0)  β”‚ ───► β”‚  (Partition ota_1)                 β”‚   β”‚
β”‚  β”‚  β€’ BLE Provisioning β”‚      β”‚  β€’ TOF / Ultrasonic / Oscillation  β”‚   β”‚
β”‚  β”‚  β€’ UDP Discovery    β”‚      β”‚  β€’ Temperature / Light             β”‚   β”‚
β”‚  β”‚  β€’ OTA Web Server   β”‚      β”‚  β€’ MQTT Data Publishing            β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Repository Structure

LabEx_V1.2/
β”‚
β”œβ”€β”€ my-app/                              # πŸ–₯️ React Frontend (PWA)
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ App.jsx                      #    Root app with routing
β”‚   β”‚   β”œβ”€β”€ pages/
β”‚   β”‚   β”‚   β”œβ”€β”€ UserDashboard.jsx        #    Main user dashboard
β”‚   β”‚   β”‚   β”œβ”€β”€ AdminDashboard.jsx       #    Admin control panel
β”‚   β”‚   β”‚   β”œβ”€β”€ ExperimentInterface.jsx  #    Universal experiment UI
β”‚   β”‚   β”‚   β”œβ”€β”€ SensorProvisioning.jsx   #    BLE sensor setup wizard
β”‚   β”‚   β”‚   β”œβ”€β”€ ProgramSensor.jsx        #    Firmware programming UI
β”‚   β”‚   β”‚   └── About.jsx               #    About page
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ Login.jsx / Signup.jsx   #    Authentication forms
β”‚   β”‚   β”‚   β”œβ”€β”€ ForgotPassword.jsx       #    Password recovery (OTP)
β”‚   β”‚   β”‚   β”œβ”€β”€ PlotlyGraph.jsx          #    Real-time graph engine
β”‚   β”‚   β”‚   β”œβ”€β”€ OSIInterface.jsx         #    Oscillation-specific UI
β”‚   β”‚   β”‚   β”œβ”€β”€ DeviceScanner.jsx        #    Device discovery UI
β”‚   β”‚   β”‚   β”œβ”€β”€ Header.jsx / Navbar.jsx  #    Navigation components
β”‚   β”‚   β”‚   └── common/                  #    Shared UI components
β”‚   β”‚   β”œβ”€β”€ experiments/
β”‚   β”‚   β”‚   β”œβ”€β”€ experimentConfig.js      #    Experiment definitions (9 types)
β”‚   β”‚   β”‚   └── experimentRegistry.js    #    Plugin system for experiments
β”‚   β”‚   β”œβ”€β”€ hooks/
β”‚   β”‚   β”‚   β”œβ”€β”€ useWebSocket.js          #    WebSocket connection hook
β”‚   β”‚   β”‚   └── usePerformance.js        #    Performance monitoring
β”‚   β”‚   β”œβ”€β”€ stores/
β”‚   β”‚   β”‚   β”œβ”€β”€ authStore.js             #    Auth state (Zustand)
β”‚   β”‚   β”‚   └── experimentStore.js       #    Experiment state (Zustand)
β”‚   β”‚   β”œβ”€β”€ context/
β”‚   β”‚   β”‚   β”œβ”€β”€ ThemeContext.jsx          #    Dark/light mode
β”‚   β”‚   β”‚   └── FullscreenContext.jsx    #    Fullscreen graph mode
β”‚   β”‚   β”œβ”€β”€ services/                    #    API service layer
β”‚   β”‚   β”œβ”€β”€ utils/                       #    API client, helpers
β”‚   β”‚   └── styles/                      #    CSS modules per page
β”‚   β”œβ”€β”€ vite.config.js                   #    Vite + PWA config
β”‚   β”œβ”€β”€ package.json
β”‚   └── server.js                        #    Production Express server
β”‚
β”œβ”€β”€ py_backend/                          # βš™οΈ Python Backend
β”‚   β”œβ”€β”€ main.py                          #    FastAPI entry point (1761 lines)
β”‚   β”œβ”€β”€ session_manager.py               #    Device registration & allocation
β”‚   β”œβ”€β”€ ws_client.py                     #    WebSocket manager for frontend
β”‚   β”œβ”€β”€ ota_manager.py                   #    Chunked OTA firmware delivery
β”‚   β”œβ”€β”€ sensor_service.py                #    ESP32 HTTP communication layer
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ mqtt_service.py              #    MQTT pub/sub + binary parsing
β”‚   β”‚   β”œβ”€β”€ udp_discovery_service.py     #    UDP broadcast device discovery
β”‚   β”‚   β”œβ”€β”€ ble_service.py               #    BLE WiFi provisioning
β”‚   β”‚   β”œβ”€β”€ user_service.py              #    User CRUD & authentication
β”‚   β”‚   β”œβ”€β”€ session_service.py           #    Token session management
β”‚   β”‚   β”œβ”€β”€ otp_service.py               #    OTP generation & verification
β”‚   β”‚   β”œβ”€β”€ file_service.py              #    File upload/download
β”‚   β”‚   β”œβ”€β”€ admin_auth_service.py        #    Admin JWT + CSRF security
β”‚   β”‚   β”œβ”€β”€ admin_user_service.py        #    Admin user management
β”‚   β”‚   └── oscillation_service.py       #    Oscillation data analysis
β”‚   β”œβ”€β”€ processor/
β”‚   β”‚   β”œβ”€β”€ processor_manager.py         #    Processor factory & lifecycle
β”‚   β”‚   β”œβ”€β”€ sensor_base.py               #    Abstract base class
β”‚   β”‚   β”œβ”€β”€ sensor_displacement.py       #    TOF distance β†’ kinematics
β”‚   β”‚   β”œβ”€β”€ sensor_oscillation.py        #    Period & frequency analysis
β”‚   β”‚   β”œβ”€β”€ sensor_disp_angle.py         #    Displacement + angle β†’ energy
β”‚   β”‚   β”œβ”€β”€ sensor_galileo.py            #    Inclined plane analysis
β”‚   β”‚   β”œβ”€β”€ sensor_temperature.py        #    Temperature conversion
β”‚   β”‚   └── sensor_video_oscillation.py  #    AI vision oscillation
β”‚   β”œβ”€β”€ config/
β”‚   β”‚   └── database.py                  #    SQLAlchemy + SQLite schema
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ config.py                    #    Paths & constants
β”‚   β”‚   β”œβ”€β”€ crypto.py                    #    Encryption utilities
β”‚   β”‚   β”œβ”€β”€ network_utils.py             #    IP/SSID detection
β”‚   β”‚   └── packet.py                    #    Binary packet codec
β”‚   β”œβ”€β”€ firmware/
β”‚   β”‚   β”œβ”€β”€ firmware_registry.json       #    Firmware name β†’ file mapping
β”‚   β”‚   └── *.bin                        #    Compiled ESP32 binaries
β”‚   β”œβ”€β”€ mosquitto.conf                   #    MQTT broker configuration
β”‚   └── requirements.txt                 #    Python dependencies
β”‚
β”œβ”€β”€ LabExpert_Sensor_ESP32_CODES/         # πŸ”Œ ESP32 Firmware (separate repo)
β”‚   β”œβ”€β”€ ESP_32_OTA/                      #    OTA bootloader
β”‚   β”œβ”€β”€ THR_Firmware_bin_Generator/      #    Temperature firmware
β”‚   β”œβ”€β”€ TOF_Firmware_bin_Generator/      #    Time-of-Flight firmware
β”‚   β”œβ”€β”€ OSI_Firmware_bin_Generator/      #    Oscillation firmware
β”‚   β”œβ”€β”€ UltraSonic_Firmware_bin_Generator/ # Ultrasonic firmware
β”‚   β”œβ”€β”€ shared/                          #    Shared ESP32 libraries
β”‚   └── README.md                        #    Detailed firmware documentation
β”‚
β”œβ”€β”€ docs/                                # πŸ“š Documentation
β”‚   β”œβ”€β”€ admin-auth-api.md                #    Admin API reference
β”‚   └── admin-auth-schema.md             #    Admin database schema
β”‚
β”œβ”€β”€ requirements.txt                     # πŸ“¦ Root Python dependencies
└── .gitignore

πŸ§ͺ Supported Experiments

# Experiment Sub-Experiments Sensor Data Output
1 πŸ“ Distance Measurement Free Fall, Modern Galileo VL53L1X TOF / HC-SR04 Distance, Velocity, Acceleration
2 πŸ”„ Oscillation Counter Simple Pendulum, Compound Pendulum LDR/Laser Gate Period, Frequency, TΒ² vs L
3 🌑️ Temperature Monitoring Live Temperature DS18B20 °C, °F, K vs Time
4 πŸ’‘ Light Intensity Intensity Monitor BH1750 Lux vs Time
5 πŸƒ Motion Analysis (AI) Simple Pendulum, Galileo Experiment Camera (Vision) Angle, Distance, Velocity

Experiment Configuration System

Each experiment is defined declaratively in experimentConfig.js:

{
  id: '1.1',
  name: 'Free Fall Experiment',
  firmware: 'TOFFFE.bin',
  dataFields: ['time', 'distance', 'velocity', 'acceleration'],
  graphConfig: { xAxis: 'time', yAxes: ['distance', 'velocity', 'acceleration'] },
  tableConfig: { columns: [...] },
  sensorOptions: [
    { type: 'TOF', label: 'TOF Sensor', firmware: 'TOFFFE.bin' },
    { type: 'ULT', label: 'ULT Sensor', firmware: 'ULTFFE.bin' }
  ],
  defaultConfig: { frequency_hz: 20, duration_s: 10 }
}

Adding a new experiment only requires editing the config file β€” no UI code changes needed.


πŸ”Œ Communication Protocols

Data Flow

ESP32 Sensor                Backend                    Frontend
    β”‚                          β”‚                          β”‚
    │── MQTT Binary Data ─────►│                          β”‚
    β”‚   (timestamp, distance,  │── Process via ──────────►│
    β”‚    sample#)               β”‚   SensorProcessor       β”‚
    β”‚                          β”‚                          β”‚
    β”‚                          │── WebSocket JSON ───────►│
    β”‚                          β”‚   (processed kinematics) β”‚
    β”‚                          β”‚                          β”‚
    │◄── MQTT Commands ───────│◄── WebSocket Commands ──│
    β”‚   (start/stop/config)    β”‚   (scan/select/config)   β”‚
    β”‚                          β”‚                          β”‚
    │◄── UDP Discovery ───────│                          β”‚
    β”‚   (broadcast @ 8888)     β”‚                          β”‚
    │── UDP Response ─────────►│                          β”‚
    β”‚   (device_id, sensor,    β”‚                          β”‚
    β”‚    IP, MAC @ 8889)       β”‚                          β”‚

MQTT Topics

Topic Pattern Direction Purpose
labexpert/{device_id}/data ESP32 β†’ Backend Sensor data (binary packed)
labexpert/{device_id}/data/binary ESP32 β†’ Backend Binary sensor packets
labexpert/{device_id}/status ESP32 β†’ Backend Device status updates
labexpert/{device_id}/config Backend β†’ ESP32 Experiment configuration
labexpert/{device_id}/command Backend β†’ ESP32 Start/Stop/Pause/Resume
labexpert/{device_id}/disconnect Backend β†’ ESP32 Cleanup & reboot to OTA

πŸ’Ύ Database Schema

SQLite database with 11 tables managed via SQLAlchemy:

erDiagram
    users {
        TEXT id PK
        TEXT name
        TEXT email UK
        TEXT password
        TEXT role
        INTEGER is_email_verified
        TEXT profile_picture
    }
    sessions {
        INTEGER id PK
        TEXT user_id FK
        TEXT token
        DATETIME expires_at
    }
    experiment_runs {
        TEXT id PK
        TEXT user_id FK
        TEXT experiment_type
        TEXT sub_experiment
        TEXT run_id
        TEXT filename
    }
    device_allocations {
        INTEGER id PK
        TEXT device_id UK
        TEXT user_id FK
        DATETIME expires_at
    }
    available_sensors {
        INTEGER id PK
        TEXT sensor_id UK
        INTEGER availability
        INTEGER online_status
        TEXT last_firmware
    }
    admin_users {
        INTEGER id PK
        TEXT email UK
        TEXT password_hash
        TEXT role
        INTEGER must_change_password
    }
    users ||--o{ sessions : has
    users ||--o{ experiment_runs : performs
    users ||--o{ device_allocations : allocates
    admin_users ||--o{ admin_sessions : has
Loading

πŸ” Security Features

Feature Implementation
User Authentication JWT tokens, bcrypt password hashing
Email Verification OTP via email (yagmail)
Admin Auth Separate JWT with CSRF protection
Password Security Complexity validation, history tracking (last 5)
Rate Limiting 5 login attempts per 5 minutes per IP
Session Management Auto-expiry, inactivity timeout (30 min admin)
CORS Dynamic origin validation for local network

πŸ› οΈ Prerequisites

Tool Version Purpose
Python 3.10+ Backend runtime
Node.js 18+ Frontend build
Mosquitto 2.0+ MQTT broker
PlatformIO Latest ESP32 firmware builds
Git Latest Version control

πŸš€ Getting Started

1. Clone the Repository

git clone <repository-url>
cd LabEx_V1.2

2. Start the MQTT Broker

# Install Mosquitto, then:
mosquitto -c py_backend/mosquitto.conf

3. Set Up the Backend

cd py_backend

# Create virtual environment
python -m venv .venv

# Activate (Windows)
.venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Create .env file
cp .env.example .env  # Or create with required vars

# Start the backend
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

The backend will:

  • Initialize the SQLite database (data/lab_expert.db)
  • Start the MQTT service (connects to Mosquitto)
  • Start UDP discovery service (port 8888/8889)
  • Seed default admin account (labexpert.us@gmail.com)

4. Set Up the Frontend

cd my-app

# Install dependencies
npm install

# Start development server
npm run dev

Access the application at http://localhost:5173

5. Production Build

cd my-app
npm run build        # Build to dist/
npm run start        # Serve via Express (port 3000)

πŸ”„ User Workflow

sequenceDiagram
    actor Student
    participant Frontend
    participant Backend
    participant MQTT as Mosquitto
    participant ESP32

    Student->>Frontend: Login / Signup
    Frontend->>Backend: POST /api/login
    Backend-->>Frontend: JWT Token

    Student->>Frontend: Select Experiment
    Frontend->>Backend: WS: scan_devices
    Backend->>ESP32: UDP Broadcast (port 8888)
    ESP32-->>Backend: UDP Response (ID, sensor, IP)
    Backend-->>Frontend: WS: device_list

    Student->>Frontend: Select Device
    Frontend->>Backend: WS: select_device
    Backend->>Backend: Allocate device to user

    Student->>Frontend: Configure & Start
    Frontend->>Backend: WS: flash_firmware
    Backend->>ESP32: HTTP OTA (chunked upload)
    ESP32-->>Backend: Reboot to experiment firmware

    Backend->>MQTT: Publish config & start command
    MQTT->>ESP32: Config + Start
    ESP32->>MQTT: Binary sensor data
    MQTT->>Backend: Forward data
    Backend->>Backend: Process via SensorProcessor
    Backend-->>Frontend: WS: processed kinematics

    Student->>Frontend: View real-time graph
    Student->>Frontend: Stop experiment
    Frontend->>Backend: WS: stop_experiment
    Backend->>MQTT: Stop command
    ESP32-->>Backend: Cleanup, reboot to OTA
Loading

🧠 Backend Service Architecture

Service File Responsibility
SessionManager session_manager.py Device registration, user↔device allocation, UDP discovery orchestration
ClientWebSocketManager ws_client.py Frontend WS connections, experiment lifecycle commands, BLE provisioning
MQTTService services/mqtt_service.py MQTT pub/sub, binary data parsing, device status forwarding
UDPDiscoveryService services/udp_discovery_service.py Periodic broadcast discovery, online device registry
OTAManager ota_manager.py Firmware selection, chunked HTTP upload to ESP32, progress tracking
SensorProcessorManager processor/processor_manager.py Factory for 6 sensor processors, per-device lifecycle
UserService services/user_service.py User CRUD, bcrypt auth, profile management
AdminAuthService services/admin_auth_service.py Admin JWT, CSRF tokens, rate limiting, password history
OTPService services/otp_service.py Email OTP generation, verification, expiry
FileService services/file_service.py Experiment data export (CSV, JSON), profile pictures
BLEService services/ble_service.py BLE scanning, WiFi credential provisioning via NimBLE

Sensor Processors

Processor Experiment Input Output
DisplacementProcessor Free Fall / Distance time, distance velocity, acceleration, smoothed curves
OscillationProcessor Simple/Compound Pendulum cut times period, frequency, TΒ² vs L
DispAngleProcessor Displacement + Angle time, distance, angle energy, forces
GalileoProcessor Modern Galileo time, distance velocity, acceleration on incline
TemperatureProcessor Temperature Monitor raw temp Β°C, Β°F, K conversions
VideoOscillationProcessor AI Motion Analysis video frames angle, position tracking

🌐 API Endpoints

User Authentication

Method Endpoint Description
POST /api/login User login (email + password)
POST /api/signup Create new account
GET /api/me Get current user profile
PUT /api/profile Update user profile
POST /api/forgot-password Send OTP to email
POST /api/verify-otp Verify OTP code
POST /api/reset-password Reset password with OTP

Admin API

Method Endpoint Description
POST /api/admin/auth/login Admin login (sets HttpOnly cookie)
GET /api/admin/auth/me Admin profile
POST /api/admin/auth/change-password Change admin password
POST /api/admin/auth/logout Admin logout (clears cookies)
GET /api/admin/users List all admin users
POST /api/admin/users Create new admin

Device & Experiment

Method Endpoint Description
GET /api/devices List available sensor devices
POST /api/devices/{id}/allocate Allocate device to user
POST /api/devices/{id}/release Release device
POST /api/experiment/configure Configure experiment parameters
POST /api/experiment/start Start data collection
POST /api/experiment/stop Stop data collection
GET /api/system/info System health & stats

WebSocket Events

Event Direction Payload
scan_devices Client β†’ Server β€”
device_list Server β†’ Client { devices: [...] }
select_device Client β†’ Server { device_id }
flash_firmware Client β†’ Server { device_id, experiment_type }
flash_progress Server β†’ Client { progress, message }
configure_experiment Client β†’ Server { config, experiment_type }
start_experiment Client β†’ Server { config }
sensor_data Server β†’ Client { time, distance, velocity, ... }
stop_experiment Client β†’ Server β€”
ble_scan Client β†’ Server β€”
ble_provision Client β†’ Server { ssid, password }

πŸ–₯️ Frontend Architecture

Tech Stack

Technology Purpose
React 19 UI components & hooks
Vite 6 Build tool & dev server
TailwindCSS 3 Utility-first styling
Plotly.js Interactive scientific graphs
Recharts Dashboard charts
Zustand Lightweight state management
React Router v7 Client-side routing
Axios HTTP client
Lucide React Icon library
react-qr-code QR code generation
Vite PWA Progressive Web App support

Route Map

Route Component Auth Description
/login Login Public User login
/signup Signup Public User registration
/forgot-password ForgotPassword Public Password recovery (OTP)
/about About Public About page
/dashboard UserDashboard Private Main user dashboard
/experiment/:id ExperimentRouter Private Dynamic experiment UI
/sensor SensorProvisioning Private BLE sensor setup
/sensor/program ProgramSensor Private Firmware programming
/admin/login AdminLogin Public Admin authentication
/admin/manage AdminManage Admin Admin management panel

πŸ“‘ ESP32 Firmware

The ESP32 firmware lives in LabExpert_Sensor_ESP32_CODES/ β€” see its own README.md for comprehensive documentation covering:

  • Dual-partition OTA bootloader architecture
  • 5 firmware generators (THR, TOF, OSI, UltraSonic, BH1750)
  • Shared libraries (LedController, NVS credentials)
  • Complete GPIO pin mapping
  • HTTP API endpoints
  • Build & flash instructions

πŸ“¦ Key Dependencies

Backend (Python)

Package Version Purpose
fastapi 0.117.1 Async web framework
uvicorn 0.24.0 ASGI server
SQLAlchemy 2.0.23 ORM & database
paho-mqtt 2.1.0 MQTT client
bcrypt 4.0.1 Password hashing
pydantic 2.6.1 Data validation
numpy / scipy Latest Scientific computation
bleak 1.1.1 BLE communication
yagmail 0.15 Email (OTP delivery)
pyotp 2.8.0 OTP generation
websockets 15.0.1 WebSocket support
python-dotenv 1.0.0 Environment config
cryptography 46.0.3 JWT token handling
pillow 11.3.0 Image processing

Frontend (Node.js)

Package Version Purpose
react 19.1.0 UI framework
vite 6.3.5 Build tool
plotly.js 3.2.0 Scientific graphing
recharts 3.2.1 Dashboard charts
zustand 5.0.8 State management
react-router-dom 7.6.2 Routing
axios 1.9.0 HTTP client
tailwindcss 3.4.1 CSS framework
vite-plugin-pwa 1.0.3 PWA support

πŸ§ͺ Running Tests

# Backend tests
cd py_backend
python -m pytest tests/

# MQTT connectivity test
python test_mqtt.py

# UDP discovery verification
python verify_discovery.py

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/new-experiment
  3. Follow the modular architecture:
    • Backend: Add new processor in processor/, register in processor_manager.py
    • Frontend: Add experiment config in experimentConfig.js β€” UI auto-generates
    • Firmware: Follow the pattern in LabExpert_Sensor_ESP32_CODES/
  4. Test all three layers (firmware β†’ backend β†’ frontend)
  5. Submit a pull request

πŸ“„ License

This project is licensed under the MIT License.

MIT License

Copyright (c) 2025 LabExpert

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Built with ❀️ for physics education β€” React Β· FastAPI Β· ESP32 Β· MQTT

About

πŸ”¬ Lab Expert is a lab experiment visualization app that helps students and researchers understand complex experimental setups through interactive simulations. It bridges theory and practice by providing clear, engaging visuals for lab procedures, making it a valuable tool for education and research.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •