{"id":28715510,"url":"https://github.com/sjnims/it8951_epaper_py","last_synced_at":"2025-06-15T02:10:17.000Z","repository":{"id":295932594,"uuid":"991678794","full_name":"sjnims/IT8951_ePaper_Py","owner":"sjnims","description":"Pure Python driver for IT8951 e-paper controller","archived":false,"fork":false,"pushed_at":"2025-06-06T20:11:00.000Z","size":488,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-14T06:52:19.547Z","etag":null,"topics":["driver","e-ink","epd","python","python-3","python3","raspberry-pi","raspberrypi","waveshare","waveshare-epaper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sjnims.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-28T02:01:08.000Z","updated_at":"2025-06-09T19:27:19.000Z","dependencies_parsed_at":"2025-06-04T06:23:13.034Z","dependency_job_id":null,"html_url":"https://github.com/sjnims/IT8951_ePaper_Py","commit_stats":null,"previous_names":["sjnims/it8951_epaper_py"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/sjnims/IT8951_ePaper_Py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sjnims%2FIT8951_ePaper_Py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sjnims%2FIT8951_ePaper_Py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sjnims%2FIT8951_ePaper_Py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sjnims%2FIT8951_ePaper_Py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sjnims","download_url":"https://codeload.github.com/sjnims/IT8951_ePaper_Py/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sjnims%2FIT8951_ePaper_Py/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259910742,"owners_count":22930713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["driver","e-ink","epd","python","python-3","python3","raspberry-pi","raspberrypi","waveshare","waveshare-epaper"],"created_at":"2025-06-15T02:10:16.225Z","updated_at":"2025-06-15T02:10:16.992Z","avatar_url":"https://github.com/sjnims.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IT8951 e-Paper Python Driver\n\n[![CI/CD](https://github.com/sjnims/IT8951_ePaper_Py/actions/workflows/ci.yml/badge.svg)](https://github.com/sjnims/IT8951_ePaper_Py/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/sjnims/IT8951_ePaper_Py/graph/badge.svg?token=BB2VKPF6YL)](https://codecov.io/gh/sjnims/IT8951_ePaper_Py)\n[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3112/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)\n[![CodeQL](https://img.shields.io/badge/CodeQL-enabled-green.svg)](https://github.com/sjnims/IT8951_ePaper_Py/security/code-scanning)\n\nA pure Python implementation of the Waveshare IT8951 e-paper controller driver for Raspberry Pi. This driver provides a clean, modern Python interface for controlling e-paper displays using the IT8951 controller chip.\n\n**New in v0.14.0:** Performance and memory optimizations! Pre-allocated arrays in hot paths, zero-copy SPI transfers, comprehensive memory monitoring utilities, and performance profiling tools. Test coverage increased to 99%.\n\n**v0.13.0:** Enhanced debug mode with 6 verbosity levels, component-specific debugging, and diagnostic context in error messages.\n\n**v0.12.0:** Comprehensive integration test suite with multi-feature workflows, error recovery, and memory management tests.\n\n## Features\n\n### What Sets This Driver Apart\n\n- **🐍 Pure Python** - No C dependencies, runs on any platform with mock mode\n- **🔋 Power Management** - Standby/sleep modes with auto-sleep timeout for battery-powered devices\n- **🎯 Smart Defaults** - 4bpp mode by default (50% less data, same quality as 8bpp)\n- **🛡️ Memory Safety** - Progressive loading for large images with automatic memory warnings\n- **🧪 Development-Friendly** - 99.18% test coverage, type hints, and mock SPI for testing without hardware\n- **⚡ Production-Ready** - Auto-alignment, VCOM calibration, A2 ghosting prevention, and comprehensive error handling\n- **📊 Performance Testing** - Built-in benchmarks for pixel packing, display operations, and memory usage\n- **🔍 Troubleshooting Tools** - Interactive diagnostics, register dumps, and guided problem resolution\n\n## Requirements\n\n- Python 3.11 or later (supports 3.11 and 3.12)\n- Raspberry Pi with SPI enabled (for hardware usage)\n- Waveshare 10.3\" e-paper HAT with IT8951 controller\n\n### Python Dependencies\n\n- `pydantic` \u003e= 2.9 - Data validation and models\n- `pillow` \u003e= 10.4 - Image processing\n- `numpy` \u003e= 1.26,\u003c2.0 - Numerical operations (stays on 1.x to avoid breaking changes)\n- `spidev` \u003e= 3.6 - SPI communication (Raspberry Pi only)\n- `RPi.GPIO` \u003e= 0.7.1 - GPIO control (optional, Raspberry Pi only)\n\n## Installation\n\n### Platform Support\n\nThis library supports multiple platforms:\n\n- **Raspberry Pi** (ARM/ARM64) - Full hardware support\n- **Linux** (x86_64) - Development with MockSPI\n- **macOS** (Intel/Apple Silicon) - Development with MockSPI\n- **Windows** - Basic compatibility with MockSPI\n\nSee [Platform Support Guide](docs/PLATFORM_SUPPORT.md) for detailed platform-specific instructions.\n\n### Using Poetry (recommended)\n\n```bash\ngit clone https://github.com/sjnims/IT8951_ePaper_Py.git\ncd IT8951_ePaper_Py\npoetry install\n\n# For Raspberry Pi users, install with GPIO support:\npoetry install -E rpi\n```\n\n### Using pip\n\n```bash\ngit clone https://github.com/sjnims/IT8951_ePaper_Py.git\ncd IT8951_ePaper_Py\npip install -e .\n\n# For Raspberry Pi with GPIO:\npip install -e \".[rpi]\"\n```\n\n## Quick Start\n\n```python\nfrom IT8951_ePaper_Py import EPaperDisplay\nfrom IT8951_ePaper_Py.constants import DisplayMode\n\n# Initialize display with VCOM voltage (check your display's FPC cable sticker)\ndisplay = EPaperDisplay(vcom=-2.0)  # Replace with your display's VCOM value\n\ntry:\n    # Initialize and get display dimensions\n    width, height = display.init()\n    print(f\"Display size: {width}x{height}\")\n\n    # Clear display to white\n    display.clear(color=0xFF)\n\n    # Display an image\n    from PIL import Image\n    img = Image.open(\"example.jpg\")\n    display.display_image(img, x=0, y=0, mode=DisplayMode.GC16)\nfinally:\n    display.close()\n```\n\n### Power Management\n\nUse the context manager for automatic power management:\n\n```python\n# Auto-sleep after 30 seconds of inactivity\nwith EPaperDisplay(vcom=-2.0) as display:\n    display.set_auto_sleep_timeout(30.0)\n    width, height = display.init()\n\n    # Display your content\n    display.display_image(img)\n\n    # Get device status including power state\n    status = display.get_device_status()\n    print(f\"Power state: {status['power_state']}\")\n\n# Display automatically enters sleep mode on exit\n```\n\n### Pixel Format\n\nThe driver supports multiple pixel formats for different use cases:\n\n```python\nfrom IT8951_ePaper_Py.constants import PixelFormat\n\n# Default: 4bpp (recommended) - 16 grayscale levels, 50% data reduction\ndisplay.display_image(img)\n\n# 8bpp - Full 256 grayscale levels\ndisplay.display_image(img, pixel_format=PixelFormat.BPP_8)\n\n# 2bpp - 4 grayscale levels, good for simple graphics\ndisplay.display_image(img, pixel_format=PixelFormat.BPP_2)\n\n# 1bpp - Binary (black/white), fastest updates for text/QR codes\ndisplay.display_image(img, pixel_format=PixelFormat.BPP_1)\n```\n\n**Performance comparison:**\n\n- **1bpp**: 1/8 data of 8bpp - ideal for text, QR codes, line art\n- **2bpp**: 1/4 data of 8bpp - good for simple graphics with 4 gray levels\n- **4bpp**: 1/2 data of 8bpp - best balance of quality and speed (default)\n- **8bpp**: Full quality - use when maximum grayscale fidelity is needed\n\n### SPI Speed Configuration\n\nThe driver automatically detects your Raspberry Pi version and selects the optimal SPI speed:\n\n- **Raspberry Pi 3 and below**: 15.625 MHz (faster)\n- **Raspberry Pi 4 and above**: 7.8125 MHz (more stable)\n\nYou can also manually override the SPI speed:\n\n```python\n# Manual speed override (10 MHz)\ndisplay = EPaperDisplay(vcom=-2.0, spi_speed_hz=10000000)\n\n# Use default auto-detection\ndisplay = EPaperDisplay(vcom=-2.0)\n```\n\n**Note**: These speeds are based on Waveshare's recommendations. Pi 4+ requires slower speeds due to hardware differences.\n\n## Examples\n\n### Basic Display\n\n```python\n# See examples/basic_display.py\npython examples/basic_display.py\n```\n\n### Image Display\n\n```python\n# Display an image file\npython examples/image_display.py path/to/image.jpg -2.0\n```\n\n### Partial Updates\n\n```python\n# Fast partial updates for dynamic content\npython examples/partial_update.py\n```\n\n### VCOM Calibration\n\n```python\n# Find optimal VCOM voltage for your display\npython examples/vcom_calibration.py\n```\n\n### Power Management Demo\n\n```python\n# Demonstrate power management features\npython examples/power_management_demo.py\n```\n\n### Performance Optimizations\n\n```python\n# 4bpp optimized display (50% data reduction)\npython examples/performance_4bpp.py\n\n# 1bpp binary display for text/QR codes\npython examples/binary_1bpp_demo.py\n\n# Progressive loading for large images\npython examples/progressive_loading_demo.py\n```\n\n### Battery-Powered Applications\n\n```python\n# Comprehensive battery-powered device example\npython examples/battery_powered_demo.py\n```\n\n### Troubleshooting\n\n```python\n# Interactive troubleshooting guide with diagnostics\npython examples/troubleshooting_demo.py\n```\n\nSee all examples in the [`examples/`](examples/) directory.\n\n## Architecture\n\nThe driver follows a layered architecture:\n\n1. **Hardware Abstraction Layer** ([`spi_interface.py`](src/IT8951_ePaper_Py/spi_interface.py))\n   - `SPIInterface` - Abstract base class\n   - `RaspberryPiSPI` - Hardware implementation\n   - `MockSPI` - Mock implementation for testing\n2. **Core Driver** ([`it8951.py`](src/IT8951_ePaper_Py/it8951.py))\n   - Low-level IT8951 controller communication\n   - Register operations and command execution\n3. **High-Level Display** ([`display.py`](src/IT8951_ePaper_Py/display.py))\n   - User-friendly display interface\n   - Image processing and alignment\n   - Automatic format conversion\n4. **Data Models** ([`models.py`](src/IT8951_ePaper_Py/models.py))\n   - Type-safe configuration with Pydantic\n   - Validation and data structures\n5. **Utilities and Helpers**\n   - [`alignment.py`](src/IT8951_ePaper_Py/alignment.py) - Pixel alignment operations\n   - [`buffer_pool.py`](src/IT8951_ePaper_Py/buffer_pool.py) - Memory buffer management\n   - [`command_utils.py`](src/IT8951_ePaper_Py/command_utils.py) - Command validation\n   - [`pixel_packing.py`](src/IT8951_ePaper_Py/pixel_packing.py) - Numpy-optimized pixel packing\n   - [`vcom_calibration.py`](src/IT8951_ePaper_Py/vcom_calibration.py) - VCOM calibration logic\n6. **Exception Hierarchy** ([`exceptions.py`](src/IT8951_ePaper_Py/exceptions.py))\n   - `IT8951Error` - Base exception\n   - `CommunicationError` - SPI communication failures\n   - `DeviceError` - Device-reported errors\n   - `InitializationError` - Initialization failures\n   - `DisplayError` - Display operation errors\n   - `IT8951MemoryError` - Memory operation failures\n   - `IT8951TimeoutError` - Operation timeouts\n   - `InvalidParameterError` - Invalid parameters\n   - `VCOMError` - VCOM voltage configuration errors\n\n## Thread Safety\n\n**Important:** The base `EPaperDisplay` class is NOT thread-safe. The IT8951 controller and SPI communication protocol do not support concurrent operations.\n\n### Using ThreadSafeEPaperDisplay (Recommended)\n\nFor multi-threaded applications, use the provided `ThreadSafeEPaperDisplay` wrapper:\n\n```python\nfrom IT8951_ePaper_Py import ThreadSafeEPaperDisplay\nimport threading\n\n# Create thread-safe display instance\ndisplay = ThreadSafeEPaperDisplay(vcom=-2.0)\n\n# Can be safely used from multiple threads\ndef worker(thread_id):\n    display.display_image(image, x=thread_id * 100, y=0)\n\nthreads = [threading.Thread(target=worker, args=(i,)) for i in range(4)]\nfor t in threads:\n    t.start()\nfor t in threads:\n    t.join()\n```\n\nThe `ThreadSafeEPaperDisplay` class:\n\n- Provides automatic thread synchronization using a reentrant lock\n- Has identical API to `EPaperDisplay` - just change the class name\n- Allows nested method calls within the same thread\n- Protects all public methods and properties\n\n### Manual Synchronization\n\nIf you prefer manual control, implement your own synchronization:\n\n```python\nimport threading\nfrom IT8951_ePaper_Py import EPaperDisplay\n\ndisplay = EPaperDisplay(vcom=-2.0)\ndisplay_lock = threading.Lock()\n\n# In each thread:\nwith display_lock:\n    display.display_image(image)\n```\n\nThread safety issues to be aware of:\n\n- SPI transactions must be atomic (chip select, data transfer)\n- Command/data sequences can be corrupted by concurrent access\n- Power state changes affect all operations\n- The busy wait mechanism assumes single-threaded access\n\nSee [Thread Safety Guide](docs/THREAD_SAFETY.md) for detailed documentation and patterns.\n\n## Display Modes\n\n- `INIT` (0) - Full initialization mode\n- `DU` (1) - Direct update (fast, monochrome)\n- `GC16` (2) - 16-level grayscale (high quality)\n- `GL16` (3) - 16-level grayscale with flashing\n- `A2` (4) - 2-level fast update\n- `GLR16` (5) - Ghost reduction 16-level (reduces ghosting artifacts)\n- `GLD16` (6) - Ghost level detection 16 (adaptive ghost compensation)\n- `DU4` (7) - Direct update 4-level (fast 4-grayscale mode)\n\n## Development\n\n### Mock Interface for Non-Pi Development\n\nThe driver includes a mock SPI interface that allows development and testing on non-Raspberry Pi systems:\n\n```python\n# The driver automatically uses MockSPI when not on a Raspberry Pi\nfrom IT8951_ePaper_Py import EPaperDisplay\n\n# Works on macOS, Windows, Linux without hardware\ndisplay = EPaperDisplay(vcom=-2.0)\n```\n\n### Setting up Development Environment\n\n```bash\n# Install all development dependencies\npoetry install --with dev\n\n# Run tests\npoetry run pytest\n\n# Run type checking\npoetry run pyright\n\n# Run linting\npoetry run ruff check .\n\n# Format code\npoetry run ruff format .\n\n# Check code complexity\npoetry run radon cc src/ -a\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npoetry run pytest\n\n# Run with coverage\npoetry run pytest --cov\n\n# Run specific test file\npoetry run pytest tests/test_display.py\n\n# Run performance benchmarks\npoetry run pytest tests/test_performance.py -v\n\n# Run numpy pixel packing benchmarks\npoetry run pytest tests/test_numpy_pixel_packing.py -v\n\n# Run with detailed timing information\npoetry run pytest --durations=10\n```\n\nThe test suite includes:\n\n- **Unit tests** for all modules with 98.35% coverage\n- **Performance benchmarks** for critical operations\n- **Pixel packing tests** for all bit depths (1bpp, 2bpp, 4bpp, 8bpp)\n- **Power management tests** for battery optimization\n- **Alignment tests** for edge cases and hardware requirements\n- **Extended display mode tests** for GLR16, GLD16, and DU4 modes\n\n### Project Structure\n\n```text\nIT8951_ePaper_Py/\n├── src/\n│   └── IT8951_ePaper_Py/\n│       ├── __init__.py          # Package initialization\n│       ├── constants.py         # Hardware constants\n│       ├── exceptions.py        # Custom exceptions\n│       ├── models.py            # Pydantic data models\n│       ├── spi_interface.py     # SPI abstraction layer\n│       ├── it8951.py            # Core driver\n│       ├── display.py           # High-level interface\n│       ├── alignment.py         # Pixel alignment utilities\n│       ├── buffer_pool.py       # Memory buffer management\n│       ├── command_utils.py     # Command validation helpers\n│       ├── pixel_packing.py     # Numpy-optimized pixel packing\n│       ├── utils.py             # General utilities\n│       └── vcom_calibration.py  # VCOM calibration logic\n├── tests/                       # Test suite\n├── examples/                    # Example scripts\n├── stubs/                       # Type stubs for external libs\n├── docs/                        # Documentation\n├── ROADMAP.md                   # Development roadmap\n├── CLAUDE.md                    # AI assistant instructions\n├── CHANGELOG.md                 # Version history\n├── CONTRIBUTING.md              # Contribution guidelines\n└── pyproject.toml               # Project configuration\n```\n\n## Error Recovery and Retry Mechanisms\n\nThe driver includes comprehensive error recovery capabilities:\n\n### Configurable Retry Policies\n\n```python\nfrom IT8951_ePaper_Py import RetryPolicy, BackoffStrategy, create_retry_spi_interface\n\n# Exponential backoff (default)\npolicy = RetryPolicy(\n    max_attempts=5,\n    delay=0.1,\n    backoff_factor=2.0,\n    backoff_strategy=BackoffStrategy.EXPONENTIAL\n)\n\n# Linear backoff for gradual retry\nlinear_policy = RetryPolicy(\n    backoff_strategy=BackoffStrategy.LINEAR,\n    max_delay=5.0  # Cap maximum delay\n)\n\n# Fixed delay with jitter to prevent thundering herd\njitter_policy = RetryPolicy(\n    backoff_strategy=BackoffStrategy.JITTER,\n    jitter_range=0.1  # ±10% randomness\n)\n\n# Create display with retry-enabled SPI\nspi = create_retry_spi_interface(retry_policy=policy)\ndisplay = EPaperDisplay(vcom=-2.0, spi_interface=spi)\n```\n\n### Error Recovery Examples\n\n```python\n# See comprehensive error recovery demonstration\npython examples/error_recovery_demo.py\n\n# Basic retry mechanism demo\npython examples/retry_demo.py\n```\n\nSee [Error Recovery Guide](docs/ERROR_RECOVERY.md) for detailed recovery procedures and best practices.\n\n## Debug Mode\n\nThe driver includes comprehensive debug logging for troubleshooting and development:\n\n### Enabling Debug Mode\n\n```python\nfrom IT8951_ePaper_Py import enable_debug, disable_debug, DebugLevel\n\n# Enable debug logging\nenable_debug(DebugLevel.DEBUG)\n\n# Use the display - will show debug output\ndisplay = EPaperDisplay(vcom=-2.0)\ndisplay.init()\n\n# Disable when done\ndisable_debug()\n```\n\n### Component-Specific Debugging\n\n```python\nfrom IT8951_ePaper_Py import set_component_debug, DebugLevel\n\n# Set different levels for different components\nset_component_debug(\"spi\", DebugLevel.TRACE)      # Very verbose SPI logging\nset_component_debug(\"display\", DebugLevel.INFO)   # General display info\nset_component_debug(\"power\", DebugLevel.DEBUG)    # Detailed power management\n```\n\n### Environment Variables\n\nConfigure debug mode via environment:\n\n```bash\n# Global debug level\nexport IT8951_DEBUG=INFO\n\n# Component-specific levels\nexport IT8951_DEBUG_SPI=TRACE\nexport IT8951_DEBUG_DISPLAY=DEBUG\n\npython your_script.py\n```\n\n### Debug Levels\n\n- `OFF` - No debug output (default)\n- `ERROR` - Only errors\n- `WARNING` - Warnings and errors\n- `INFO` - General information\n- `DEBUG` - Detailed debug info\n- `TRACE` - Very detailed trace info\n\nSee `examples/debug_mode_demo.py` for comprehensive examples.\n\n## Documentation\n\n- [Platform Support](docs/PLATFORM_SUPPORT.md) - Multi-platform installation and compatibility\n- [Performance Guide](docs/PERFORMANCE_GUIDE.md) - Optimization tips and benchmarks\n- [Display Modes](docs/DISPLAY_MODES.md) - Detailed explanation of all display modes\n- [Power Management](docs/POWER_MANAGEMENT.md) - Battery optimization and power states\n- [Memory Safety](docs/MEMORY_SAFETY.md) - Memory management best practices\n- [Bit Depth Support](docs/BIT_DEPTH_SUPPORT.md) - Using different pixel formats\n- [Thread Safety](docs/THREAD_SAFETY.md) - Multi-threading considerations and solutions\n- [Error Recovery](docs/ERROR_RECOVERY.md) - Retry policies and recovery procedures\n- [Hardware Setup](docs/HARDWARE_SETUP.md) - Raspberry Pi GPIO connections and troubleshooting\n- [Migration Guide](docs/MIGRATION_GUIDE.md) - Migrating from the C driver to Python\n- [Best Practices](docs/BEST_PRACTICES.md) - Production deployment and optimization tips\n- [ATS Monitoring](docs/ATS_MONITORING.md) - Automated Test Selection CI/CD optimization\n- [Docstring Style Guide](docs/DOCSTRING_EXAMPLES.md) - Examples of Google-style docstrings for contributors\n\n## Roadmap\n\nSee our [Development Roadmap](ROADMAP.md) for completed and planned features. **Phase 13.2 diagnostic enhancements are now complete**, featuring debug mode with configurable verbosity levels and enhanced error messages with diagnostic context.\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n### Code Style\n\n- Follow PEP 8\n- Use type hints for all functions\n- Add docstrings (Google style)\n- Run `ruff check` and `ruff format` before committing\n- Ensure all tests pass before submitting PR\n\n### CI/CD\n\nThis project uses GitHub Actions for continuous integration:\n\n- **Linting**: ruff (linting + formatting), pyright\n- **Testing**: pytest with coverage on multiple platforms\n  - Ubuntu (x86_64) - Python 3.11, 3.12, 3.13\n  - macOS (Intel/ARM) - Python 3.13\n  - ARM64 (via QEMU) - Python 3.11\n  - Windows - Basic compatibility check\n- **Security**: CodeQL for comprehensive security analysis\n- **Complexity**: radon for maintainability metrics\n- **Performance**: Benchmark tests for critical paths\n- **Coverage**: 98.35% code coverage maintained\n\nPRs must pass all checks before merging.\n\n## Troubleshooting Guide\n\n### Common Issues\n\n#### Display Not Initializing\n\n1. **Check VCOM voltage**\n\n   ```python\n   # VCOM must match your display's specification (check FPC cable sticker)\n   display = EPaperDisplay(vcom=-2.0)  # Replace with your display's value\n   ```\n\n2. **Verify SPI is enabled**\n\n   ```bash\n   # Enable SPI on Raspberry Pi\n   sudo raspi-config\n   # Navigate to Interface Options \u003e SPI \u003e Enable\n\n   # Verify SPI devices exist\n   ls /dev/spi*\n   # Should show: /dev/spidev0.0  /dev/spidev0.1\n   ```\n\n3. **Check connections**\n   - Ensure HAT is properly seated on GPIO pins\n   - Verify FPC cable is fully inserted and locked\n\n#### Blurry or Unclear Display\n\nEnable enhanced driving mode for long cables or display quality issues:\n\n```python\ndisplay = EPaperDisplay(vcom=-2.0, enhance_driving=True)\n```\n\n#### Ghosting Issues\n\n1. **With A2 mode (fast updates)**\n\n   ```python\n   # Enable auto-clear to prevent ghosting\n   display = EPaperDisplay(vcom=-2.0, a2_refresh_limit=10)\n   ```\n\n2. **General ghosting**\n\n   ```python\n   # Perform full clear\n   display.clear()\n   ```\n\n#### Permission Errors\n\n```bash\n# Add user to spi and gpio groups\nsudo usermod -a -G spi,gpio $USER\n# Logout and login again for changes to take effect\n\n# Alternative: run with sudo (not recommended for production)\nsudo python your_script.py\n```\n\n#### Image Alignment Warnings\n\nThe IT8951 requires specific pixel alignment:\n\n```python\n# For 1bpp mode, use 32-pixel alignment\nx = (x // 32) * 32\nwidth = ((width + 31) // 32) * 32\n\n# For other modes, use 4-pixel alignment (handled automatically)\n```\n\n#### Memory Errors\n\nFor large images or limited memory:\n\n```python\n# Use lower bit depth\ndisplay.display_image(img, pixel_format=PixelFormat.BPP_4)  # Default\n\n# Use partial updates\ndisplay.display_partial(img, x=100, y=100, width=200, height=200)\n\n# Use progressive loading for very large images (v0.4.0+)\ndisplay.display_image_progressive(\n    large_image,\n    chunk_height=256,  # Process in 256-pixel chunks\n    pixel_format=PixelFormat.BPP_4\n)\n```\n\nThe progressive loading feature processes images in chunks to reduce memory usage:\n\n- Ideal for images larger than 16MB\n- Automatically handles alignment requirements\n- Configurable chunk size for memory/performance tradeoff\n\n#### Slow Performance\n\n1. **Use appropriate pixel format**\n\n   ```python\n   # 4bpp is 2x faster than 8bpp with minimal quality loss\n   display.display_image(img)  # Uses 4bpp by default\n   ```\n\n2. **Choose the right display mode**\n\n   ```python\n   # Fast updates\n   display.display_image(img, mode=DisplayMode.DU)    # ~260ms\n   display.display_image(img, mode=DisplayMode.A2)    # ~120ms\n\n   # Quality updates\n   display.display_image(img, mode=DisplayMode.GC16)  # ~450ms\n   ```\n\n#### Mock Mode Issues\n\nWhen developing on non-Raspberry Pi systems:\n\n```python\n# The driver automatically uses MockSPI\ndisplay = EPaperDisplay(vcom=-2.0)  # Works on any platform\n\n# To explicitly use mock mode\nfrom IT8951_ePaper_Py.spi_interface import MockSPI\nmock_spi = MockSPI()\ndisplay = EPaperDisplay(vcom=-2.0, spi_interface=mock_spi)\n```\n\n### Debugging Tips\n\n1. **Enable debug logging**\n\n   ```python\n   import logging\n   logging.basicConfig(level=logging.DEBUG)\n\n   # Now you'll see timing information:\n   # DEBUG: init completed in 523.45ms\n   # DEBUG: display_image completed in 467.23ms\n   ```\n\n2. **Check device info**\n\n   ```python\n   display = EPaperDisplay(vcom=-2.0)\n   width, height = display.init()\n   print(f\"Display size: {width}x{height}\")\n   print(f\"VCOM: {display.get_vcom()}V\")\n   ```\n\n3. **Verify register values**\n\n   ```python\n   # Dump important registers\n   regs = display.dump_registers()\n   for name, value in regs.items():\n       print(f\"{name}: 0x{value:04X}\")\n   ```\n\n### Getting Help\n\n1. Check the [examples](examples/) directory for working code\n2. Read the [performance guide](docs/PERFORMANCE_GUIDE.md)\n3. Search [existing issues](https://github.com/sjnims/IT8951_ePaper_Py/issues)\n4. Create a new issue with:\n   - Python version (`python --version`)\n   - Raspberry Pi model (`cat /proc/cpuinfo | grep Model`)\n   - Display model and VCOM voltage\n   - Minimal code to reproduce\n   - Debug log output\n\n## Acknowledgements\n\n- Based on [Waveshare IT8951 C driver](https://github.com/waveshareteam/IT8951-ePaper)\n- Inspired by other e-paper Python libraries\n- Thanks to the Raspberry Pi and Python communities\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsjnims%2Fit8951_epaper_py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsjnims%2Fit8951_epaper_py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsjnims%2Fit8951_epaper_py/lists"}