Skip to content

xatang/PyUnit

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

65 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

PyUnit

Docker Build Docker Pulls Docker Image Size License

PyUnit is a custom firmware for iDryer Unit written in Python.

โœจ Features

  • ๐ŸŒก๏ธ Real-time monitoring of temperature and humidity
  • ๐ŸŽฏ PID temperature control with configurable parameters
  • ๐Ÿ”„ Multiple drying presets with timer and storage modes
  • ๐Ÿ“Š Interactive charts with adaptive downsampling
  • ๐Ÿ”Œ Klipper integration via Moonraker API
  • ๐ŸŽจ LED control for visual status indicators
  • ๐Ÿšช Servo control for automated door operation
  • ๐Ÿ“ฑ Responsive web interface built with Angular
  • ๐Ÿ”— WebSocket real-time updates
  • ๐Ÿ“‹ Embed pages for Klipper HTTP camera integration
  • ๐Ÿค– G-code macro generation for Klipper
  • ๐Ÿณ Multi-platform Docker images (amd64, arm64, arm/v7, arm/v8)

๐Ÿ“ธ Screenshots

Dashboard Overview

Dashboard Main dashboard with all dryers overview and real-time monitoring

Dryer Dashboard

Dryer Dashboard Detailed dryer view with temperature/humidity charts and control panel

Presets Management

Presets Preset configuration with timer and storage modes

Fluidd Integration

Fluidd Integration PyUnit embedded control panel in Fluidd/Mainsail interface

๐Ÿš€ Quick Start

One-Command Installation

git clone https://github.com/xatang/PyUnit.git
cd PyUnit
chmod +x run.sh
./run.sh

That's it! Access PyUnit at http://YOUR_IP:5000

The script will automatically:

  • โœ… Install Docker and Docker Compose (if needed)
  • โœ… Detect your IP address
  • โœ… Configure the environment
  • โœ… Download pre-built Docker image
  • โœ… Start the application

Installation time: 1-3 minutes (no compilation required!)

First-Time Setup Wizard

On your first visit to PyUnit, you'll be greeted by a 3-step setup wizard that guides you through initial configuration:

Step 1: Configure Moonraker Connection

  • Enter your Moonraker IP address
    • For Docker users: Use your machine's network IP (e.g., 192.168.1.100)
    • For local installations: You can use 127.0.0.1
  • Default port: 7125
  • Test connection before saving

Step 2: Add Your First Dryer

  • Configure all hardware components:
    • Heater (must be configured in Klipper)
    • Fan (PWM control)
    • Temperature and humidity sensor
    • LED indicators
    • Servo door control
  • All components must be pre-configured in your Klipper configuration

Step 3: Start Using PyUnit

  • Once configured, access the dashboard
  • Monitor and control your dryer units

Note: The wizard can be skipped using "Skip setup for now" if you want to configure manually later.

Requirements

  • OS: Linux (Ubuntu, Debian, Raspbian, Armbian)
  • Architecture:
    • amd64 (x86_64) - Intel/AMD 64-bit
    • arm64 (aarch64) - ARM 64-bit
    • arm/v7 - ARMv7 32-bit
    • arm/v8 - ARMv8 32-bit
  • RAM: 256MB minimum (512MB recommended)
  • Disk: ~1GB for Docker image

Additionally, you can add the following commands to the Fluidd or Mainsail console filters to avoid a flood of messages during firmware operation.

SET_LED LED=[led_name] INDEX=
SET_HEATER_TEMPERATURE HEATER=[heater_name]
SET_SERVO SERVO=[servo_name]

Updates

To update to the latest version:

cd PyUnit
./run.sh

Updates preserve your configuration and IP settings automatically.

Uninstallation

To completely remove PyUnit (container, volumes, images, network):

cd PyUnit
chmod +x uninstall.sh
./uninstall.sh

This will remove:

  • Docker container pyunit
  • Docker volume pyunit_pyunit_data (all data will be lost!)
  • Docker network pyunit_pyunit_network
  • Docker images xatang/pyunit:*

Note: Local files (pyunit.db, logs) are NOT deleted automatically. To remove them:

rm -f pyunit.db pyunit.db-wal pyunit.db-shm app.log dryer.log

๐Ÿ—๏ธ Architecture

Backend (FastAPI + Python 3.11)

  • FastAPI - Modern async web framework
  • SQLAlchemy - ORM with SQLite database
  • Alembic - Database migrations
  • WebSockets - Real-time bidirectional communication
  • Uvicorn - ASGI server (hardcoded: 0.0.0.0:5000)
  • Simple-PID - PID controller for temperature regulation
  • aiohttp - Async HTTP client for Moonraker API

Key Components:

  • api/endpoints/ - Modular REST API endpoints
  • api/cruds/ - Database CRUD operations
  • api/workers/ - Background status monitoring
  • api/tools/ - Dryer control & Moonraker integration
  • main.py - Application entry point (fixed host/port)

Frontend (Angular 18)

  • Angular 18 - Standalone components architecture
  • Runtime Configuration - IP/URLs set at container startup
  • Highcharts - Interactive data visualization
  • Bootstrap 5 - Dark theme UI
  • RxJS - Reactive state management
  • WebSocket - Real-time data subscriptions

Port Mapping:

  • Internal: Always 5000 (hardcoded in main.py)
  • External: Configurable via .env PORT variable
  • Example: PORT=8080 maps 8080:5000 (host:container)

โš™๏ธ Configuration

Environment Variables

The .env file is automatically created with your detected IP:

# Backend Configuration
LOG_LEVEL=INFO                    # Logging verbosity
DRYER_LOG_LEVEL=INFO              # Dryer-specific logging
CLEAR_LOGS_ON_STARTUP=True        # Clear logs on startup

# External Access (auto-configured by run.sh)
PORT=5000                         # External port (host side)
API_URL=http://192.168.1.100:5000/api  # Frontend API URL
WS_URL=ws://192.168.1.100:5000/api     # WebSocket URL

Note: HOST=0.0.0.0 and internal PORT=5000 are hardcoded in main.py and not configurable.

Docker Compose

docker-compose.yml uses .env automatically:

services:
  pyunit:
    image: xatang/pyunit:latest  # Auto-detected by run.sh
    ports:
      - "${PORT:-5000}:5000"     # External:Internal
    environment:
      - API_URL=${API_URL}       # For runtime config.js
      - WS_URL=${WS_URL}
    volumes:
      - ./pyunit.db:/app/pyunit.db
      - ./app.log:/app/app.log
      - ./dryer.log:/app/dryer.log

Changing the External Port

Edit .env:

PORT=8080
API_URL=http://192.168.1.100:8080/api
WS_URL=ws://192.168.1.100:8080/api

Then restart:

sudo docker compose up -d

๐ŸŽฎ Usage

Dashboard

Real-time Monitoring:

  • Live temperature and humidity charts
  • Current dryer status and remaining time
  • Heater and servo state indicators
  • Historical data with time range selector (5m, 10m, 1h, 6h, 12h, All)

Starting a Drying Cycle:

  1. Select a dryer from the list
  2. Choose a preset
  3. Click Start - the dryer will begin the drying process

Configuration

Moonraker Integration:

  1. Go to Config โ†’ Moonraker
  2. Set Moonraker IP
  3. Add API key (if authentication enabled)
  4. Save configuration
  5. Add new dryer
  6. Assign presets to new dryer

Klipper Integration

Example Configuration:

A complete Klipper configuration example is available in config_and_macros/U1.cfg.example. This file contains:

  • Heater configuration ([heater_generic])
  • Temperature sensor setup ([temperature_sensor])
  • LED control ([neopixel])
  • Servo configuration ([servo])
  • G-code macros for dryer control

โš ๏ธ Important: All module and sensor names in Klipper configuration must be lowercase:

  • โœ… Correct: idryer_u1_heater, idryer_u1_air, srv_u1
  • โŒ Wrong: IDryer_U1_Heater, IDRYER_U1_AIR, SRV_U1

G-code Macros:

  1. To control the drying process via gcode macro, your printer must have the gcode_shell_command extension installed.
  2. After installation gcode_shell_command go to dryer detail page
  3. Expand Klipper G-code Macros
  4. Configure Python script path
  5. Copy macros to printer.cfg
  6. Use in Klipper:
    OFF_DRYER ID=1
    PRESET_DRYER ID=1 PRESET_ID=5

HTTP Camera Embed:

  1. Expand Klipper Embed Pages
  2. Copy embed URLs
  3. Add to Moonraker config:
    [camera pyunit_control]
    location: dryer
    service: http
    aspect_ratio: 4:3
    stream_url: http://192.168.1.100:5000/embed/dryer/1/control
    
    [camera pyunit_chart]
    location: dryer
    service: http  
    aspect_ratio: 4:3
    stream_url: http://192.168.1.100:5000/embed/dryer/1/chart

๐Ÿ› ๏ธ Service Management

# View status
sudo docker compose ps

# Start/stop/restart
sudo docker compose up -d
sudo docker compose down
sudo docker compose restart

# View logs (live)
sudo docker compose logs -f

# View logs (last 100 lines)
sudo docker compose logs --tail=100

# Check resource usage
sudo docker stats pyunit

๐Ÿ“š API Documentation

Interactive documentation available at:

  • Swagger UI: http://192.168.1.100:5000/docs
  • ReDoc: http://192.168.1.100:5000/redoc

Key Endpoints

Dashboard:

  • GET /api/dashboard - Overview of all dryers
  • GET /api/dashboard/dryer/{id} - Dryer details with chart data
  • POST /api/dashboard/dryer/{id}/preset - Start preset on dryer
  • POST /api/dashboard/dryer/{id}/reset - Reset dryer to pending

Configuration:

  • GET /api/config/dryers - List all dryers
  • GET /api/config/moonraker - Moonraker settings
  • PUT /api/config/moonraker - Update Moonraker config

Presets:

  • GET /api/presets - List all presets
  • POST /api/presets - Create new preset
  • PUT /api/presets/{id} - Update preset
  • DELETE /api/presets/{id} - Delete preset

Logs:

  • GET /api/logs - Retrieve application logs

WebSocket:

  • WS /api/ws - Real-time status updates

๐Ÿ“ Project Structure

PyUnit/
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/
โ”‚       โ””โ”€โ”€ docker-build.yml     # CI/CD pipeline for multi-platform builds
โ”œโ”€โ”€ .venv/                       # Python virtual environment (local dev)
โ”œโ”€โ”€ __pycache__/                 # Python bytecode cache
โ”œโ”€โ”€ alembic/                     # Database migrations
โ”‚   โ”œโ”€โ”€ versions/                # Migration scripts
โ”‚   โ”‚   โ””โ”€โ”€ 5a91b07ca6c5_initdb.py
โ”‚   โ”œโ”€โ”€ env.py                   # Alembic environment
โ”‚   โ”œโ”€โ”€ README                   # Alembic documentation
โ”‚   โ””โ”€โ”€ script.py.mako           # Migration template
โ”œโ”€โ”€ api/                         # Backend API
โ”‚   โ”œโ”€โ”€ cruds/                   # Database CRUD operations
โ”‚   โ”‚   โ”œโ”€โ”€ common_crud.py       # Common operations (logs cleanup)
โ”‚   โ”‚   โ”œโ”€โ”€ dryer_crud.py        # Dryer management
โ”‚   โ”‚   โ”œโ”€โ”€ moonraker_config_crud.py  # Moonraker config
โ”‚   โ”‚   โ””โ”€โ”€ preset_crud.py       # Preset management
โ”‚   โ”œโ”€โ”€ endpoints/               # API route handlers
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py          # Router aggregation
โ”‚   โ”‚   โ”œโ”€โ”€ common.py            # Health check, WebSocket
โ”‚   โ”‚   โ”œโ”€โ”€ config_page.py       # Dryer & Moonraker config
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard_page.py    # Dashboard & dryer control
โ”‚   โ”‚   โ”œโ”€โ”€ logs_page.py         # Logs retrieval
โ”‚   โ”‚   โ””โ”€โ”€ presets_page.py      # Preset CRUD
โ”‚   โ”œโ”€โ”€ schemas/                 # Pydantic validation models
โ”‚   โ”‚   โ”œโ”€โ”€ dryer_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ dryer_config_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ heater_config_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ humidity_config_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ led_config_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ moonraker_config_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ preset_schema.py
โ”‚   โ”‚   โ”œโ”€โ”€ servo_config_schema.py
โ”‚   โ”‚   โ””โ”€โ”€ temperature_config_schema.py
โ”‚   โ”œโ”€โ”€ tools/                   # Core control logic
โ”‚   โ”‚   โ”œโ”€โ”€ dryer_control.py     # Dryer state machine & PID control
โ”‚   โ”‚   โ””โ”€โ”€ moonraker_api.py     # Moonraker HTTP client
โ”‚   โ”œโ”€โ”€ workers/                 # Background tasks
โ”‚   โ”‚   โ””โ”€โ”€ status_worker.py     # Periodic status polling & control
โ”‚   โ”œโ”€โ”€ database.py              # SQLAlchemy setup & migrations
โ”‚   โ”œโ”€โ”€ logger.py                # Logging configuration
โ”‚   โ”œโ”€โ”€ models.py                # SQLAlchemy ORM models
โ”‚   โ””โ”€โ”€ websocket_manager.py     # WebSocket connection manager
โ”œโ”€โ”€ config_and_macros/
โ”‚   โ””โ”€โ”€ idryer_api.py            # Python script for Klipper G-code integration
โ”œโ”€โ”€ web/                         # Frontend (Angular 18)
โ”‚   โ”œโ”€โ”€ public/                  # Static assets
โ”‚   โ”‚   โ””โ”€โ”€ assets/
โ”‚   โ”‚       โ””โ”€โ”€ imgs/            # Images
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ app/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ common-ui/       # Shared UI components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ guards/          # Route guards
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ setup.guard.ts  # Setup completion check
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ pages/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ configs/     # Configuration pages
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ dryer-config/
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ moonraker-config/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ dashboard/   # Dashboard & dryer details
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ dashboard/
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ dryer-detail/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ embed/       # Klipper embed pages
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ dryer-chart/
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ dryer-control/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ logs/        # Logs viewer
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ presets/     # Preset CRUD
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ preset-editor/
โ”‚   โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ presets-list/
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ welcome/     # First-time setup wizard
โ”‚   โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ welcome.html
โ”‚   โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ welcome.scss
โ”‚   โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ welcome.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ services/        # Angular services
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ dryer-config.service.ts
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ moonraker-config.service.ts
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ presets.service.ts
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ websocket.service.ts
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.config.ts    # Angular app configuration
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.html         # Root component template
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.initializer.ts  # Runtime config loader
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.routes.ts    # Route definitions
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ app.scss         # Global styles
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ app.ts           # Root component
โ”‚   โ”‚   โ”œโ”€โ”€ environments.ts      # Runtime config (auto-generated by update-env.js)
โ”‚   โ”‚   โ”œโ”€โ”€ index.html           # HTML entry point
โ”‚   โ”‚   โ”œโ”€โ”€ main.ts              # Bootstrap with APP_INITIALIZER
โ”‚   โ”‚   โ””โ”€โ”€ styles.scss          # Global SCSS styles
โ”‚   โ”œโ”€โ”€ angular.json             # Angular CLI configuration
โ”‚   โ”œโ”€โ”€ package.json             # NPM dependencies
โ”‚   โ”œโ”€โ”€ tsconfig.json            # TypeScript configuration
โ”‚   โ”œโ”€โ”€ tsconfig.app.json        # App-specific TS config
โ”‚   โ”œโ”€โ”€ tsconfig.spec.json       # Test TS config
โ”‚   โ””โ”€โ”€ update-env.js            # Pre-build script (generates environments.ts)
โ”œโ”€โ”€ .dockerignore                # Docker build exclusions
โ”œโ”€โ”€ .env                         # Environment config (auto-created by run.sh)
โ”œโ”€โ”€ .gitignore                   # Git ignore patterns
โ”œโ”€โ”€ alembic.ini                  # Alembic configuration
โ”œโ”€โ”€ build.sh                     # Local Docker image build script
โ”œโ”€โ”€ docker-compose.yml           # Docker Compose service definition
โ”œโ”€โ”€ Dockerfile                   # Multi-stage Docker build (Node + Python)
โ”œโ”€โ”€ entrypoint.sh                # Container startup script (creates config.js)
โ”œโ”€โ”€ main.py                      # FastAPI application entry point
โ”œโ”€โ”€ pyunit.db                    # SQLite database (created by run.sh)
โ”œโ”€โ”€ requirements.txt             # Python dependencies
โ”œโ”€โ”€ run.sh                       # Installation/update script
โ””โ”€โ”€ README.md                    # This file

๐Ÿ”ฌ Technologies

Backend Stack

  • FastAPI 0.104+ - Modern async web framework
  • Python 3.11 - Programming language
  • SQLAlchemy 2.0+ - SQL toolkit and ORM
  • Alembic 1.12+ - Database migration tool
  • Pydantic 2.0+ - Data validation using Python type hints
  • simple-pid 2.0+ - PID controller implementation
  • aiohttp 3.9+ - Async HTTP client for Moonraker
  • uvicorn 0.24+ - ASGI server implementation
  • WebSockets - Real-time bidirectional communication

Frontend Stack

  • Angular 18 - Modern web application framework
  • TypeScript 5.0+ - Typed JavaScript superset
  • Highcharts 11+ - Interactive charting library
  • Bootstrap 5.3 - Responsive UI framework
  • Bootstrap Icons 1.11+ - Icon library
  • RxJS 7.8+ - Reactive programming library
  • Standalone Components - Modern Angular architecture

DevOps & Tools

  • Docker - Containerization
  • Docker Compose - Multi-container orchestration
  • GitHub Actions - CI/CD automation
  • Docker Buildx - Multi-platform image builds
  • SQLite - Embedded database

About

Custom python firmware for iDryer Unit

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •