LensFort is a local, camera-based security monitoring application with:
- A Python backend that handles camera control, person detection, and video lifecycle.
- A React frontend that provides system control, recordings browsing, playback, download, and deletion.
This document is a developer-focused guide that explains how the system works end-to-end, how to run it, and where to change behavior safely.
At a high level, the system performs these operations:
- User arms the system in the web UI.
- Backend starts camera loop and runs person detection on live frames.
- If a person is detected, frames are written to a temporary video file.
- When detections stop for a configured frame window, recording closes.
- Closed recording is post-processed with ffmpeg and saved into local storage.
- Frontend fetches logs from backend and renders recordings by date.
- User can view details, download, and delete recordings from the dashboard.
backend/main.pyexposes REST APIs, serves video files, and controls theCamerasingleton.backend/camera.pycontains the camera worker thread, OpenCV DNN inference, and record-start/stop logic.backend/storage.pyfinalizes clips asynchronously and stores them inbackend/local_videos.backend/notifications.pyprovides optional Twilio SMS notification helper.
frontend/src/App.jsdefines routes and application shell.frontend/src/ArmControl.jsxcontrols arm/disarm state and live stats.frontend/src/RecordingsPage.jsxhandles logs retrieval, filtering, grouping, and calendar browsing.frontend/src/Details.jsxhandles playback plus download/delete actions.frontend/src/Log.jsxrenders recording cards and previews.
- Frontend calls
POST /armandPOST /disarm. - Backend forwards those actions to
Camera.arm()andCamera.disarm(). Camerathread lifecycle is protected with a lock (state_lock) to avoid duplicate starts/stops.
- OpenCV MobileNet SSD model files:
backend/models/config.txtbackend/models/mobilenet_iter_73000.caffemodel
- Person class filter:
- Class ID
15 - Confidence threshold:
0.5
- Class ID
- While armed:
- Reads camera frame
- Runs forward pass
- Detects person boxes
- Starts recording when first person appears
- Keeps writing frames while detections continue
- Stops recording after
50consecutive non-detection frames
- Temporary clip path is created in
backend/videos/. - On clip close,
storage.handle_detection(path)runs in a background daemon thread. save_locally()inbackend/storage.py:- Scales clip to 720px height via ffmpeg
- Writes final file to
backend/local_videos/ - Uses timestamp filename format:
DD-MM-YY-HH-MM-SS.mp4
GET /get-logsscansbackend/local_videos/.- Timestamp is parsed from filename and returned as ISO datetime (
date). - Supports filters:
startDate/endDate(ISO strings or date-only)- legacy
daysoffset
LensFort/
backend/
.sample.env
__init__.py
camera.py
main.py
notifications.py
storage.py
models/
config.txt
mobilenet_iter_73000.caffemodel
local_videos/ # runtime-generated recordings
frontend/
package.json
package-lock.json
public/
src/
App.js
ArmControl.jsx
ArmControl.css
Sidebar.jsx
Sidebar.css
RecordingsPage.jsx
RecordingsPage.css
Log.jsx
Log.css
Details.jsx
Details.css
index.js
index.css
design/
Sequence Diagram.pdf
System Diagram.pdf
User Interface Design.pdf
requirements.txt
.gitignore
-
GET /- Returns welcome text.
-
GET /get-armed- Returns current armed state.
- Response example:
{"armed": false}
-
GET /camera-status- Returns camera summary status.
- Response example:
{"active": false, "status": "Standby"}
-
POST /arm- Arms the camera worker.
-
POST /disarm- Disarms the camera worker.
-
GET /get-logs- Query params:
startDateendDatedays(legacy)
- Response:
{"logs": [{"url": "/local_videos/<file>.mp4", "date": "<iso>"}]}
- Query params:
-
GET /local_videos/<filename>- Streams/serves video for playback.
-
GET /download-recording/<filename>- Forces recording download as attachment.
-
DELETE /delete-recording/<filename>- Deletes a recording file.
- Response example:
{"message": "Recording deleted", "filename": "..."}
POST /motion_detected- Accepts body with
urland forwards tosend_notification(). - This endpoint is available for external integrations or future hooks.
- Accepts body with
/->ArmControl/recordings->RecordingsPage/details->Details
- Polls armed status every 10 seconds.
- Shows:
- current armed/disarmed state
- camera status
- recordings count
- last motion timestamp
- Fetches all logs from backend.
- Supports:
- daily view
- all recordings view
- calendar-based date selection
- previous/next day navigation
- date grouping and sorting
- Plays selected recording via
react-player. - Shows metadata and file name.
- Supports:
- download action (
GET /download-recording/...) - delete action (
DELETE /delete-recording/...)
- download action (
Copy backend/.sample.env to backend/.env and set values:
TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKENTWILIO_RECEIVE_NUMBERTWILIO_SEND_NUMBER
notifications.py loads these values through python-dotenv.
- Python 3.11+
- Node.js and npm
- ffmpeg installed and available on PATH
From repository root:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
npm --prefix frontend installBackend:
.\.venv\Scripts\python.exe backend/main.pyFrontend:
npm --prefix frontend startURLs:
- Frontend:
http://localhost:3000 - Backend:
http://127.0.0.1:5000
- The backend camera loop is stateful and thread-backed. Prefer small, targeted changes in
camera.py. - The file naming convention in
local_videosis part of the API contract for log timestamps. - Keep
local_videosand cache/artifact folders out of git (already handled in.gitignore). - If you change frontend routes, update direct navigation assumptions in
Details.jsxandRecordingsPage.jsx.
- Ensure no other app is holding camera device
0. - Verify camera permissions in OS privacy settings.
- This project frontend is nested; use:
npm --prefix frontend start
- Confirm backend is running.
- Confirm files exist under
backend/local_videos. - Check
GET /get-logsresponse in browser/network tab.
- Ensure
Detailsreceives a valid recording URL. - Confirm backend route accessibility:
/download-recording/<file>/delete-recording/<file>
- Add automated backend tests for API routes and filename parsing.
- Add frontend component/integration tests for recordings filters and actions.
- Add configurable detection threshold via env var or settings API.
- Add structured logging and request correlation IDs.
- Add Docker support for reproducible local setup.
- Add GitHub Actions CI for lint, test, and build checks.