Skip to content

Latest commit

 

History

History
205 lines (155 loc) · 6.67 KB

File metadata and controls

205 lines (155 loc) · 6.67 KB

Vaillant Screen Reader

License: MIT

Computer vision system that reads Vaillant heater LCD displays from camera snapshots, extracting temperature and status icon states.

Features

  • Temperature recognition - reads 2-digit temperature (tens + ones) from the LCD
  • 5 status icons - detects Burn, Heating, Hot Water, Pump, and Gas Valve states
  • 95% accuracy overall, 98.6% per-task accuracy
  • Fast inference - under 10ms per image (~1000 images/sec)
  • JSON output mode - single-line JSON for easy bash/script integration
  • Automatic image validation - rejects black, overexposed, or corrupted images

Quick Start

# Clone the repository
git clone https://github.com/frozer/vaillant-screen-reader.git
cd vaillant-screen-reader

# Create and activate virtual environment
python -m venv venv
source venv/bin/activate   # Linux/macOS
# or
venv\Scripts\activate      # Windows

# Install dependencies
pip install -r requirements.txt

# Run inference on an image
python lcd_reader/lcd_reader_dl.py --image path/to/image.jpg

Usage

Human-Readable Output

python lcd_reader/lcd_reader_dl.py --image path/to/image.jpg
============================================================
LCD READING RESULT (Deep Learning)
============================================================

Temperature: 47 degrees
  Digit 1: 4 (confidence: 98.54%)
  Digit 2: 7 (confidence: 99.94%)

Status Icons:
  Burn        : ON  (confidence: 100.00%)
  Heating     : ON  (confidence: 100.00%)
  Hotwater    : ON  (confidence: 100.00%)
  Pump        : ON  (confidence: 100.00%)
  Gasvalve    : ON  (confidence: 100.00%)
============================================================

JSON Output (for Scripts)

python motion_reader.py --filename path/to/image.jpg
{"temperature":47,"isGasBurning":true,"isHeating":true,"isHotWater":true,"isInternalPumpRunning":true,"isGasValveOpened":true}

Exit codes: 0 = success, 1 = error. See MOTION_INTEGRATION.md for full documentation.

Python API

from lcd_reader.lcd_reader_dl import LCDReaderDL

reader = LCDReaderDL(model_dir='lcd_reader/models_sklearn')
result = reader.read_lcd('path/to/image.jpg')

print(f"Temperature: {result['temperature']}°")
print(f"Digit 1: {result['digit1']['value']} ({result['digit1']['confidence']:.1%})")
print(f"Burn: {result['burn']['state']} ({result['burn']['confidence']:.1%})")

Result format:

{
    'temperature': '47',
    'digit1': {'value': 4, 'confidence': 0.99},
    'digit2': {'value': 7, 'confidence': 0.99},
    'burn':     {'state': True, 'confidence': 1.0},
    'heating':  {'state': True, 'confidence': 1.0},
    'hotwater': {'state': True, 'confidence': 1.0},
    'pump':     {'state': True, 'confidence': 1.0},
    'gasvalve': {'state': True, 'confidence': 1.0},
    'success': True
}

JSON Wrapper (motion_reader.py)

Designed for bash scripts, cron jobs, and Motion event handlers:

# Basic usage
python motion_reader.py --filename /path/to/image.jpg

# With confidence threshold
python motion_reader.py --filename /path/to/image.jpg --min-confidence 0.95

# Bash integration
METADATA=$(python motion_reader.py --filename "${IMAGE_PATH}" 2>/dev/null)
if [ $? -eq 0 ]; then
    TEMP=$(echo "${METADATA}" | jq -r '.temperature')
    echo "Temperature: ${TEMP}°C"
fi

See MOTION_INTEGRATION.md for error handling, integration examples, and deployment guidance.

How It Works

The system uses a 3-stage pipeline:

  1. LCD Detection - Locates the LCD region using dual Canny edge detection with multi-criteria scoring and expected-position fallback
  2. Region Extraction - Extracts 7 regions from the detected LCD using percentage-based layout: digit1 (tens), digit2 (ones), burn, heating, hotwater, pump, gasvalve
  3. Classification - 7 independent scikit-learn MLP models (512-256-128 neurons each) classify each extracted region

Models are stored as .pkl files in lcd_reader/models_sklearn/ (~350 MB total).

Project Structure

vaillant-screen-reader/
├── lcd_reader/
│   ├── lcd_reader_dl.py            # Main inference pipeline
│   ├── lcd_segmentation_full.py    # LCD detection and region extraction
│   ├── train_sklearn.py            # Model training pipeline
│   ├── README.md                   # Detailed LCD reader documentation
│   └── models_sklearn/             # 7 trained MLP models (.pkl)
├── motion_reader.py                # JSON output wrapper for scripts
├── generate_training_csv.py        # Auto-label new images using current models
├── research/
│   ├── prepare_full_dataset.py     # Dataset generation with augmentation
│   ├── test_on_original_images.py  # End-to-end evaluation
│   └── *.md                        # Research notes and reports
├── requirements.txt
├── MOTION_INTEGRATION.md           # Motion/bash integration guide
├── CLAUDE.md                       # AI assistant context
└── LICENSE

Retraining

To improve accuracy or add support for new temperature ranges:

1. Label new images

python generate_training_csv.py --source-dir path/to/new/images --output new_labels.csv

Manually verify the CSV, then merge into source_data/training_set_v3.csv.

2. Regenerate the dataset

python research/prepare_full_dataset.py

3. Train models

python lcd_reader/train_sklearn.py --task all --dataset research/dataset --output-dir lcd_reader/models_sklearn

4. Validate

python research/test_on_original_images.py

Training takes ~25 minutes for all 7 tasks on CPU. See lcd_reader/README.md for details.

Performance

Metric Value
Overall accuracy 95%
Per-task accuracy 98.6%
Temperature accuracy 95%
Icon accuracy 95-100%
Inference time <10ms per image
Average confidence 98-99%
Model size ~350 MB (7 models)

Limitations

  • Temperature range: Trained on 42-81 C; may not generalize outside this range
  • Icon bias: Heating and Pump icons are always ON in training data (no OFF examples exist)
  • Rare digits: Some digit classes have very few training samples and may be confused with similar digits
  • Dark images: ~30% of camera snapshots are pitch-black (LCD off / camera in dark) and are automatically rejected
  • Display detection: Requires the LCD border to be visible for edge-based detection; falls back to expected-position crop otherwise

License

This project is licensed under the MIT License. See LICENSE for details.