dewey/birdhomie

Automated bird watching, with classifications and insights for UniFi Protect.

27

stars

47

commits

Python

primary language

Feb 27, 2026

updated

birding
classification
unifi
Browse cluster: BirdNET Wildlife Audio Analysis

README

Birdhomie

Bird detection and classification system for UniFi Protect with web interface.

Birdhouse with UniFi camera

Screenshots

HomeInsightsSpecies DetailFace LabelingSpecies Correction
HomeInsightsSpeciesLabelingSpecies Correction

Features

  • Automatic bird detection using YOLOv8l
  • Species classification using BioCLIP-2
  • Face detection and annotation for bird portraits
  • UniFi Protect integration for automatic video download
  • Web interface for viewing detections and species
  • Species information from iNaturalist and Wikipedia
  • Visit tracking and photo galleries
  • Split visit support for tracking multiple birds in a single visit
  • Dashboard with charts and statistics visualization
  • Manual labeling interface for reviewing face annotations
  • Internationalization support (English, German)

The easiest way to run Birdhomie is with Docker. All settings have sensible defaults - you only need to configure your UniFi Protect credentials.

1. Create docker-compose.yml

services:
  birdhomie:
    image: ghcr.io/dewey/birdhomie:latest
    container_name: birdhomie
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      - birdhomie-data:/app/data
    environment:
      # Required: UniFi Protect credentials
      - UFP_ADDRESS=192.168.1.1
      - UFP_USERNAME=your-username
      - UFP_PASSWORD=your-password
      - UFP_CAMERA_ID=your-camera-id

volumes:
  birdhomie-data:

2. Configure UniFi Protect Credentials

Update the four required environment variables:

VariableDescription
UFP_ADDRESSIP address of your UniFi Protect NVR
UFP_USERNAMELocal Access Only user username
UFP_PASSWORDLocal Access Only user password
UFP_CAMERA_IDCamera ID (find in Protect: Settings → Camera → Advanced)

To create a Local Access Only user, go to your UniFi Protect web UI and create a new user with "Full Management" permissions.

3. Start the Application

docker compose up -d

Access the web interface at http://localhost:5000

Manual Installation

If you prefer running without Docker:

Prerequisites

  • macOS 13+ or Linux
  • Python 3.13+
  • uv for package management
  • UniFi Protect NVR with a camera configured for smart detection
  • (Optional) direnv for automatic environment variable loading

Setup

# Install uv if needed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone and install
git clone https://github.com/dewey/birdhomie
cd birdhomie
uv sync

# Configure environment
cp .envrc.example .envrc
# Edit .envrc with your UniFi Protect credentials

# If using direnv
direnv allow

# Or source manually
source .envrc

# Run in development mode
make dev

The application will be available at http://127.0.0.1:5001

Configuration

All configuration options have sensible defaults. Only UniFi Protect credentials are required.

Required Settings

VariableDescription
UFP_ADDRESSIP address of your UniFi Protect NVR
UFP_USERNAMELocal Access Only user username
UFP_PASSWORDLocal Access Only user password
UFP_CAMERA_IDCamera ID to monitor

Optional Settings

VariableDefaultDescription
UFP_DETECTION_TYPESmotionDetection types to monitor
UFP_SSL_VERIFY0Verify SSL certificates (set to 1 to enable)
UFP_DOWNLOAD_INTERVAL_MINUTES60How often to check for new events
PROCESSOR_INTERVAL_MINUTES5How often to process files
PROCESSOR_WORKERS1Parallel video processing workers
MIN_SPECIES_CONFIDENCE0.85Minimum confidence for species ID (0.0-1.0)
MIN_DETECTION_CONFIDENCE0.80Minimum confidence for bird detection (0.0-1.0)
FRAME_SKIP5Process every Nth frame
FILE_RETENTION_DAYS30Days to keep input files after successful processing
UFP_INITIAL_SYNC_DAYS30Days to look back on initial sync
GUNICORN_WORKERS2Number of web server workers (production)
PORT5000Web server port
NNPACK_DISABLE0Set to 1 for CPUs without AVX2/FMA support
BIRDHOMIE_DB_DIRdata/Directory for the SQLite database file

Development Settings

VariableDefaultDescription
FLASK_DEBUG0Enable debug mode with hot reloading
SECRET_KEYdev-secret-keyFlask session secret (change for production)
FACE_ANNOTATION_BATCH_SIZE100Batch size for face annotation

Storage Layout

By default, everything lives under a single data/ directory:

data/
├── birdhomie.db        # SQLite database
├── input/              # Downloaded videos
├── output/             # Processed results and crops
├── species_images/     # Cached species images
└── models/             # ML models

If you need to store the database on a separate volume (for example to avoid overlapping Docker mounts), set BIRDHOMIE_DB_DIR to a different path:

environment:
  - BIRDHOMIE_DB_DIR=/app/db
volumes:
  - birdhomie-db:/app/db        # Database on fast storage
  - birdhomie-files:/app/data   # Large files on bulk storage

When BIRDHOMIE_DB_DIR is not set, the database is stored in data/ alongside everything else.

Web Interface

Access the web interface at http://localhost:5000 (Docker) or http://127.0.0.1:5001 (manual).

Pages:

  • / - Dashboard with recent visits and species
  • /species - List of all detected species
  • /species/<id> - Species detail page with photos and visits
  • /visits/<id> - Individual visit details with video player
  • /visits/<id>/split - Split a visit when multiple birds are detected
  • /files - List of all processed files
  • /tasks - Background task status
  • /labeling - Manual labeling interface for face annotations
  • /labeling/stats - Labeling progress and statistics
  • /settings - Application settings

Merging Duplicate Files

UniFi Protect occasionally creates multiple overlapping motion detection events for the same bird activity due to a known bug. Birdhomie provides a merge feature to consolidate duplicates:

  1. Navigate to the duplicate file's detail page
  2. Select the target file from the "Merge with another file" dropdown
  3. Click "Merge" to mark the duplicate as ignored

What happens when you merge:

  • The source file is marked with status ignored
  • All visits from the source file are soft-deleted (marked with deleted_at timestamp)
  • The video file remains on disk for potential re-processing if needed
  • You can undo by clicking "Process this file anyway" on the ignored file's page

UniFi Protect Integration

The application automatically downloads smart detection events from UniFi Protect at the configured interval (default: every 60 minutes).

Manual Trigger

You can trigger downloads manually from the Tasks page in the web interface or via API:

curl http://localhost:5000/tasks/trigger/unifi_download

Development

Running in Development Mode

source .envrc  # If not using direnv
make dev

This compiles translations, enables hot reload, and runs on http://127.0.0.1:5001.

Syncing Production Data for Testing

To test with real production data locally, you can sync your server's data directory using rsync:

  1. Configure sync settings in your .envrc:

    export SYNC_REMOTE=ubuntu@your-server.example.com:/home/ubuntu/services/birdhomie/data
    
  2. Run the sync command:

    make sync-data
    

This will download the database, models, processed files, and species images to your local ./data/ directory. The logs/ directory is automatically excluded from sync.

Prerequisites:

  • SSH access to your server with public key authentication configured
  • rsync installed locally (pre-installed on macOS and most Linux distributions)

Available Make Commands

CommandDescription
make devRun with hot reloading
make runRun in normal mode
make compile-translationsCompile .po to .mo files
make extract-translationsExtract translatable strings
make update-translationsUpdate translation catalogs
make migrateRun pending migrations
make processRun file processor manually
make sync-dataSync production data locally for testing
make cleanClean generated files
make helpShow available commands

Translations

Currently supported languages: English (en), German (de)

To add translations:

make extract-translations
make update-translations
# Edit src/birdhomie/translations/<lang>/LC_MESSAGES/messages.po
make compile-translations

Troubleshooting

Missing Environment Variables

Make sure you've configured the required UniFi Protect credentials in your .envrc or docker-compose.yml.

Port Already in Use

Change the port mapping in docker-compose.yml or stop the conflicting process.

High CPU Usage on Older CPUs

If you're running on a CPU without AVX2/FMA support (Intel pre-Haswell/2013, AMD pre-Excavator/2015), you may experience high CPU usage during model inference. Set NNPACK_DISABLE=1 in your environment to disable NNPACK optimizations.

License

MIT License - see LICENSE for details.

Contributors

dewey

47 commits

dewey/birdhomie

Automated bird watching, with classifications and insights for UniFi Protect.

27

stars

47

commits

Python

primary language

Feb 27, 2026

updated

birding
classification
unifi
Browse cluster: BirdNET Wildlife Audio Analysis

README

Birdhomie

Bird detection and classification system for UniFi Protect with web interface.

Birdhouse with UniFi camera

Screenshots

HomeInsightsSpecies DetailFace LabelingSpecies Correction
HomeInsightsSpeciesLabelingSpecies Correction

Features

  • Automatic bird detection using YOLOv8l
  • Species classification using BioCLIP-2
  • Face detection and annotation for bird portraits
  • UniFi Protect integration for automatic video download
  • Web interface for viewing detections and species
  • Species information from iNaturalist and Wikipedia
  • Visit tracking and photo galleries
  • Split visit support for tracking multiple birds in a single visit
  • Dashboard with charts and statistics visualization
  • Manual labeling interface for reviewing face annotations
  • Internationalization support (English, German)

The easiest way to run Birdhomie is with Docker. All settings have sensible defaults - you only need to configure your UniFi Protect credentials.

1. Create docker-compose.yml

services:
  birdhomie:
    image: ghcr.io/dewey/birdhomie:latest
    container_name: birdhomie
    restart: unless-stopped
    ports:
      - "5000:5000"
    volumes:
      - birdhomie-data:/app/data
    environment:
      # Required: UniFi Protect credentials
      - UFP_ADDRESS=192.168.1.1
      - UFP_USERNAME=your-username
      - UFP_PASSWORD=your-password
      - UFP_CAMERA_ID=your-camera-id

volumes:
  birdhomie-data:

2. Configure UniFi Protect Credentials

Update the four required environment variables:

VariableDescription
UFP_ADDRESSIP address of your UniFi Protect NVR
UFP_USERNAMELocal Access Only user username
UFP_PASSWORDLocal Access Only user password
UFP_CAMERA_IDCamera ID (find in Protect: Settings → Camera → Advanced)

To create a Local Access Only user, go to your UniFi Protect web UI and create a new user with "Full Management" permissions.

3. Start the Application

docker compose up -d

Access the web interface at http://localhost:5000

Manual Installation

If you prefer running without Docker:

Prerequisites

  • macOS 13+ or Linux
  • Python 3.13+
  • uv for package management
  • UniFi Protect NVR with a camera configured for smart detection
  • (Optional) direnv for automatic environment variable loading

Setup

# Install uv if needed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone and install
git clone https://github.com/dewey/birdhomie
cd birdhomie
uv sync

# Configure environment
cp .envrc.example .envrc
# Edit .envrc with your UniFi Protect credentials

# If using direnv
direnv allow

# Or source manually
source .envrc

# Run in development mode
make dev

The application will be available at http://127.0.0.1:5001

Configuration

All configuration options have sensible defaults. Only UniFi Protect credentials are required.

Required Settings

VariableDescription
UFP_ADDRESSIP address of your UniFi Protect NVR
UFP_USERNAMELocal Access Only user username
UFP_PASSWORDLocal Access Only user password
UFP_CAMERA_IDCamera ID to monitor

Optional Settings

VariableDefaultDescription
UFP_DETECTION_TYPESmotionDetection types to monitor
UFP_SSL_VERIFY0Verify SSL certificates (set to 1 to enable)
UFP_DOWNLOAD_INTERVAL_MINUTES60How often to check for new events
PROCESSOR_INTERVAL_MINUTES5How often to process files
PROCESSOR_WORKERS1Parallel video processing workers
MIN_SPECIES_CONFIDENCE0.85Minimum confidence for species ID (0.0-1.0)
MIN_DETECTION_CONFIDENCE0.80Minimum confidence for bird detection (0.0-1.0)
FRAME_SKIP5Process every Nth frame
FILE_RETENTION_DAYS30Days to keep input files after successful processing
UFP_INITIAL_SYNC_DAYS30Days to look back on initial sync
GUNICORN_WORKERS2Number of web server workers (production)
PORT5000Web server port
NNPACK_DISABLE0Set to 1 for CPUs without AVX2/FMA support
BIRDHOMIE_DB_DIRdata/Directory for the SQLite database file

Development Settings

VariableDefaultDescription
FLASK_DEBUG0Enable debug mode with hot reloading
SECRET_KEYdev-secret-keyFlask session secret (change for production)
FACE_ANNOTATION_BATCH_SIZE100Batch size for face annotation

Storage Layout

By default, everything lives under a single data/ directory:

data/
├── birdhomie.db        # SQLite database
├── input/              # Downloaded videos
├── output/             # Processed results and crops
├── species_images/     # Cached species images
└── models/             # ML models

If you need to store the database on a separate volume (for example to avoid overlapping Docker mounts), set BIRDHOMIE_DB_DIR to a different path:

environment:
  - BIRDHOMIE_DB_DIR=/app/db
volumes:
  - birdhomie-db:/app/db        # Database on fast storage
  - birdhomie-files:/app/data   # Large files on bulk storage

When BIRDHOMIE_DB_DIR is not set, the database is stored in data/ alongside everything else.

Web Interface

Access the web interface at http://localhost:5000 (Docker) or http://127.0.0.1:5001 (manual).

Pages:

  • / - Dashboard with recent visits and species
  • /species - List of all detected species
  • /species/<id> - Species detail page with photos and visits
  • /visits/<id> - Individual visit details with video player
  • /visits/<id>/split - Split a visit when multiple birds are detected
  • /files - List of all processed files
  • /tasks - Background task status
  • /labeling - Manual labeling interface for face annotations
  • /labeling/stats - Labeling progress and statistics
  • /settings - Application settings

Merging Duplicate Files

UniFi Protect occasionally creates multiple overlapping motion detection events for the same bird activity due to a known bug. Birdhomie provides a merge feature to consolidate duplicates:

  1. Navigate to the duplicate file's detail page
  2. Select the target file from the "Merge with another file" dropdown
  3. Click "Merge" to mark the duplicate as ignored

What happens when you merge:

  • The source file is marked with status ignored
  • All visits from the source file are soft-deleted (marked with deleted_at timestamp)
  • The video file remains on disk for potential re-processing if needed
  • You can undo by clicking "Process this file anyway" on the ignored file's page

UniFi Protect Integration

The application automatically downloads smart detection events from UniFi Protect at the configured interval (default: every 60 minutes).

Manual Trigger

You can trigger downloads manually from the Tasks page in the web interface or via API:

curl http://localhost:5000/tasks/trigger/unifi_download

Development

Running in Development Mode

source .envrc  # If not using direnv
make dev

This compiles translations, enables hot reload, and runs on http://127.0.0.1:5001.

Syncing Production Data for Testing

To test with real production data locally, you can sync your server's data directory using rsync:

  1. Configure sync settings in your .envrc:

    export SYNC_REMOTE=ubuntu@your-server.example.com:/home/ubuntu/services/birdhomie/data
    
  2. Run the sync command:

    make sync-data
    

This will download the database, models, processed files, and species images to your local ./data/ directory. The logs/ directory is automatically excluded from sync.

Prerequisites:

  • SSH access to your server with public key authentication configured
  • rsync installed locally (pre-installed on macOS and most Linux distributions)

Available Make Commands

CommandDescription
make devRun with hot reloading
make runRun in normal mode
make compile-translationsCompile .po to .mo files
make extract-translationsExtract translatable strings
make update-translationsUpdate translation catalogs
make migrateRun pending migrations
make processRun file processor manually
make sync-dataSync production data locally for testing
make cleanClean generated files
make helpShow available commands

Translations

Currently supported languages: English (en), German (de)

To add translations:

make extract-translations
make update-translations
# Edit src/birdhomie/translations/<lang>/LC_MESSAGES/messages.po
make compile-translations

Troubleshooting

Missing Environment Variables

Make sure you've configured the required UniFi Protect credentials in your .envrc or docker-compose.yml.

Port Already in Use

Change the port mapping in docker-compose.yml or stop the conflicting process.

High CPU Usage on Older CPUs

If you're running on a CPU without AVX2/FMA support (Intel pre-Haswell/2013, AMD pre-Excavator/2015), you may experience high CPU usage during model inference. Set NNPACK_DISABLE=1 in your environment to disable NNPACK optimizations.

License

MIT License - see LICENSE for details.

Contributors

dewey

47 commits

Languages

Python

61.9%

HTML

37.3%