Skip to content

machug/brewsignal

Repository files navigation

BrewSignal

CI Version Python License

A modern web interface for monitoring fermentation hydrometers on Raspberry Pi. Supports Tilt, iSpindel, and GravityMon devices.

Dashboard

Quick Install (Raspberry Pi)

git clone https://github.com/machug/brewsignal.git
cd brewsignal
python3 -m venv venv && source venv/bin/activate
pip install -e .
uvicorn backend.main:app --host 0.0.0.0 --port 8080

Features

  • Multi-Device Support - Tilt (BLE), iSpindel (HTTP), GravityMon (HTTP) hydrometers
  • Real-time Monitoring - Live SG and temperature readings via WebSocket
  • Historical Charts - Interactive uPlot charts with crosshair tooltips, 1H/6H/24H/7D/30D time ranges
  • Calibration - Linear interpolation (Tilt) and polynomial calibration (iSpindel/GravityMon)
  • Unit Conversion - Display gravity as SG, Plato, or Brix; temperature as °C or °F
  • RSSI Filtering - Filter weak Bluetooth signals to reduce noise from distant devices
  • Reading Smoothing (v2.4.0) - Configurable moving average filter to reduce sensor noise
  • Outlier Validation (v2.4.0) - Physical impossibility checks reject invalid readings
  • Machine Learning Pipeline (v2.5.0) - Advanced predictive fermentation analytics
    • Kalman Filtering - Optimal noise reduction for SG/temp/RSSI measurements
    • Anomaly Detection - Automatic stuck fermentation and temperature spike detection
    • Curve Fitting - Exponential decay model predicts final gravity and completion time
    • Model Predictive Control - Intelligent heater control with overshoot prevention
    • Per-Device State Isolation - Separate ML pipelines prevent cross-contamination
  • Home Assistant Integration - Display ambient temperature/humidity from HA sensors
  • MQTT Publishing (v2.10.0) - Publish fermentation data to Home Assistant via MQTT auto-discovery
    • Automatic sensor creation in Home Assistant when batches start fermenting
    • Sensors: gravity, temperature, ABV, status, days fermenting, heater/cooler state
    • Compatible with voice assistants (Alexa, Google Home) via Home Assistant
    • Fire-and-forget publishing - MQTT failures don't block reading storage
  • Dual-Mode Temperature Control (v2.4.0) - Independent heater AND cooler control per batch
    • Heating-only, cooling-only, or full dual-mode operation
    • Batch-specific temperature targets and hysteresis settings
    • Manual override controls (Force ON/OFF) per device per batch
    • Real-time heater and cooler state monitoring with visual indicators
    • Mutual exclusion logic prevents simultaneous heating and cooling
    • Minimum 5-minute cycle protection for equipment safety
  • Batch Lifecycle Management (v2.4.0) - Soft delete, restoration, and data maintenance
    • Tab-based navigation (Active, Completed, Deleted)
    • Orphaned data detection and cleanup
    • Safe batch deletion with preview mode
  • Weather Alerts - Predictive alerts when forecast temps may affect fermentation
  • BeerXML Import & Batch Tracking - Import recipes with full ingredients, link readings to batches, track against targets
  • Yeast Library (v2.8.0) - Comprehensive yeast strain database with 449+ strains
    • Scraped from Beer Maverick with detailed fermentation data
    • Filter by producer, type (ale/lager/wild), form (dry/liquid), and flocculation
    • Temperature ranges, attenuation, and alcohol tolerance for each strain
    • Batch yeast assignment with ability to override recipe yeast
    • Search and browse yeast strains with detailed property cards
  • AI Brewing Assistant (v2.9.0) - Conversational AI for brewing guidance
    • AG-UI protocol-based streaming interface for real-time responses
    • Tool-Augmented - Access to yeast library, style guides, inventory, fermentation data
    • Cross-Thread Memory - Search and recall information from previous conversations
    • Web Access - Fetch brewing resources and documentation from the web
    • Chat Management - Rename threads, persistent conversation history
    • Powered by configurable LLM backend (OpenAI, Anthropic, etc. via LiteLLM)
  • Data Export - Download all readings as CSV
  • Dark Theme - Easy on the eyes during late-night brew checks

Device Pairing (v2.3.0+)

Tilt devices must be paired before readings are logged. This prevents data pollution from nearby devices.

  • Navigate to Devices page to pair/unpair devices
  • Only paired devices log readings and can be assigned to batches
  • Unpaired devices still appear on dashboard with live readings

Machine Learning Pipeline (v2.5.0)

BrewSignal includes an advanced ML pipeline for predictive fermentation analytics. Each Tilt maintains isolated state to prevent cross-contamination.

Components

Kalman Filtering - Optimal state estimation for noisy sensor data

  • Extended Kalman Filter (EKF) tracks SG, temperature, and RSSI
  • Adaptive process noise scaling based on measurement intervals
  • Provides filtered values and velocity/acceleration estimates

Anomaly Detection - Rule-based detection of fermentation issues

  • Stuck fermentation (no SG change over 24+ hours)
  • Temperature spikes (>5°F increase in <1 hour)
  • Signal drops (RSSI below -90 dBm)
  • Early warning system for intervention

Curve Fitting - Exponential decay model for predictions

  • Predicts final gravity (FG) from historical SG trajectory
  • Estimates hours remaining until fermentation completes
  • Automatic model retraining as data accumulates

Model Predictive Control (MPC) - Intelligent temperature control

  • Learns thermal model from heating/cooling data
  • Predicts temperature trajectory over 2-hour horizon
  • Computes optimal heater action with 10x overshoot penalty
  • Prevents temperature swings and wasted energy

Configuration

from backend.ml.config import MLConfig
from backend.ml.pipeline_manager import MLPipelineManager

# Configure ML components (all enabled by default)
config = MLConfig(
    enable_kalman_filter=True,
    enable_anomaly_detection=True,
    enable_predictions=True,
    enable_mpc=True,
)

# Create pipeline manager (one instance per device)
manager = MLPipelineManager(config=config)

# Process a reading
result = manager.process_reading(
    device_id="RED",
    sg=1.050,
    temp=68.0,
    rssi=-60,
    time_hours=24.0,
    ambient_temp=65.0,
    heater_on=True,
    target_temp=70.0,
)

# Result structure:
# {
#   "kalman": {
#     "sg_filtered": 1.0498,
#     "temp_filtered": 68.1,
#     "rssi_filtered": -60.2,
#     "sg_velocity": -0.002,  # SG/hour
#   },
#   "anomaly": {
#     "is_anomaly": False,
#     "reason": None,
#   },
#   "predictions": {
#     "fitted": True,
#     "predicted_fg": 1.012,
#     "hours_remaining": 72.5,
#   },
#   "mpc": {
#     "heater_on": True,
#     "predicted_temp": 69.8,
#     "has_model": True,
#   }
# }

Dependencies

ML features require additional packages (installed automatically with pip install -e '.[dev]'):

  • numpy - Numerical computing
  • filterpy - Kalman filter implementation
  • scipy - Optimization and curve fitting
  • scikit-learn - Machine learning utilities

Validation

Validate ML pipeline on Raspberry Pi:

ssh pi@192.168.4.218
cd /opt/brewsignal
source .venv/bin/activate

# Run validation script
python validate_ml_isolation.py

# Check service logs
sudo journalctl -u brewsignal -n 100 --no-pager | grep -E "(ML|Kalman|MPC)"

See ML_VALIDATION_GUIDE.md for comprehensive validation procedures.

Requirements

  • Raspberry Pi (3B+ or newer recommended)
  • Python 3.11+
  • Bluetooth adapter (built-in or USB) for Tilt devices
  • Supported hydrometer: Tilt, iSpindel, or GravityMon

Quick Start

Installation

# Clone the repository
git clone https://github.com/machug/brewsignal.git
cd brewsignal

# Create virtual environment and install
python3 -m venv venv
source venv/bin/activate
pip install -e .

# Run the server
uvicorn backend.main:app --host 0.0.0.0 --port 8080

Access the UI at http://<raspberry-pi-ip>:8080

Systemd Service (Production)

# Copy service file
sudo cp deploy/brewsignal.service /etc/systemd/system/

# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable brewsignal
sudo systemctl start brewsignal

Configuration

Environment Variables

Variable Description Default
SCANNER_MOCK Enable mock scanner for development false
SCANNER_FILES_PATH Path to TiltPi JSON files (legacy mode) -
SCANNER_RELAY_HOST IP of remote TiltPi to relay from -

Scanner Modes

  1. BLE Mode (default) - Direct Bluetooth scanning for Tilt devices
  2. Mock Mode - Simulated readings for development (SCANNER_MOCK=true)
  3. File Mode - Read from TiltPi JSON files (SCANNER_FILES_PATH=/home/pi)
  4. Relay Mode - Fetch from remote TiltPi (SCANNER_RELAY_HOST=192.168.1.100)

Reading Smoothing (v2.4.0)

Configure in System Settings:

  • Smoothing Enabled - Apply moving average filter to raw readings
  • Smoothing Samples - Number of samples for moving average (default: 5)

Smoothing is applied after calibration but before storage, benefiting all consumers (charts, exports, Home Assistant).

Temperature Control

Configure per batch in Batch form:

  • Heating-only Mode - Set only heater_entity_id from Home Assistant
  • Cooling-only Mode - Set only cooler_entity_id from Home Assistant
  • Dual-mode - Set both for full temperature regulation
  • Temperature Target - Desired fermentation temperature
  • Hysteresis - Temperature buffer to prevent oscillation (symmetric for heat/cool)
  • Manual Override - Force heater/cooler ON/OFF for testing

Control logic:

  • Heater turns ON when temp <= (target - hysteresis), OFF when temp >= (target + hysteresis)
  • Cooler turns ON when temp >= (target + hysteresis), OFF when temp <= (target - hysteresis)
  • Mutual exclusion enforced (heater and cooler never run simultaneously)
  • Minimum 5-minute cycle time protects compressor equipment

Batch Management

Batch Statuses

  • Planning - Pre-fermentation planning phase. Device can be assigned and readings are visible on dashboard for OG validation, but readings are NOT stored in database.
  • Fermenting - Active fermentation. Readings are logged to database and linked to batch. Temperature control is active.
  • Conditioning - Post-fermentation conditioning/cold crash phase. Readings continue to be logged for temperature monitoring. Temperature control remains active.
  • Completed - Batch is finished and packaged. Readings are no longer stored in database. Temperature control is stopped.

Reading Storage Rules

  • Readings are ONLY stored when batch status is "Fermenting" or "Conditioning"
  • Live readings always visible on dashboard (via WebSocket) regardless of status
  • Device must be paired for readings to appear on dashboard
  • Planning phase allows OG validation without database pollution
  • Completed phase stops logging to preserve final state

Batch Lifecycle (v2.4.0)

Tab-Based Navigation:

  • Active Tab - Shows batches with status "planning" or "fermenting" (not deleted)
  • Completed Tab - Shows batches with status "completed" or "conditioning" (not deleted)
  • Deleted Tab - Shows soft-deleted batches (restorable)

Soft Delete:

  • Batches can be soft-deleted to preserve historical data
  • Soft-deleted batches are hidden from active views but restorable
  • Readings remain linked to soft-deleted batches

Hard Delete:

  • Permanently removes batch and cascades to all linked readings
  • Use with caution - this operation cannot be undone

Data Maintenance:

  • Access /system/maintenance to detect orphaned readings
  • Orphaned readings are linked to soft-deleted batches
  • Preview cleanup operations (dry-run mode) before executing
  • Safe cleanup only removes readings for deleted batches

Yeast Library (v2.8.0)

BrewSignal includes a comprehensive yeast strain database with 449+ strains scraped from Beer Maverick.

Features

  • Browse & Search - Full-text search across strain names and producers
  • Filter by Properties - Producer, type (ale/lager/wild/hybrid), form (dry/liquid), flocculation
  • Detailed Strain Cards - Each strain displays:
    • Fermentation temperature range (°C)
    • Attenuation range (%)
    • Flocculation (low/medium/high/very_high)
    • Alcohol tolerance
    • Producer and product ID
  • Batch Integration - Assign yeast strains to batches, overriding recipe yeast if desired

Data Source

Yeast data is scraped from Beer Maverick using scripts/scrape_beermaverick.py and stored in backend/seed/yeast_strains.json. The database is seeded on application startup.

Updating Yeast Data:

# Re-scrape yeast data from Beer Maverick
python scripts/scrape_beermaverick.py

# Refresh database (requires app restart or API call)
curl -X POST http://localhost:8080/api/yeast/refresh

Producers

The database includes strains from major yeast producers:

  • White Labs (WLP series)
  • Wyeast (WY series)
  • Fermentis (SafAle, SafLager)
  • Lallemand (LalBrew)
  • Imperial Yeast
  • Omega Yeast Labs
  • Escarpment Labs
  • Mangrove Jack's
  • And many more...

AI Brewing Assistant (v2.9.0)

BrewSignal includes an AI-powered brewing assistant that can help with recipe development, fermentation monitoring, and brewing questions.

Features

  • Tool-Augmented Responses - The assistant has direct access to:

    • Yeast strain database (449+ strains with fermentation characteristics)
    • BJCP style guidelines (116 beer styles)
    • Hop and fermentable reference libraries
    • Your inventory (hops, yeast, equipment)
    • Active fermentation data and ML predictions
    • Ambient conditions and temperature control status
  • Cross-Thread Memory - Search and recall information from previous conversations

    • Ask about recipes discussed in other chats
    • Reference past fermentation advice
    • The assistant can search thread titles and message content
  • Web Access - Fetch brewing resources from the web

    • Look up specific brewing articles or documentation
    • Access recipe information from URLs you provide
  • Chat Management

    • Rename conversation threads when topics shift
    • Persistent conversation history with sidebar navigation
    • Create new chats without losing previous conversations

Configuration

Configure the assistant in System SettingsAI Assistant:

  1. Provider - Select your LLM provider (OpenAI, Anthropic, Ollama, etc.)
  2. API Key - Enter your API key (stored securely in the database)
  3. Model - Choose the model to use (e.g., gpt-4o, claude-sonnet-4-20250514)

Environment Variables (alternative to UI configuration):

  • API keys can also be set via environment variables (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
  • The UI will detect and indicate when an env var key is being used
  • Keys entered in the UI override environment variables

For Ollama (local/self-hosted):

  • Install Ollama on your system: https://ollama.ai
  • Pull a model: ollama pull llama3.2
  • Select "Ollama" as provider in settings (no API key required)

The assistant uses LiteLLM for provider abstraction, supporting OpenAI, Anthropic, Ollama, Azure, and other backends.

Available Tools

Tool Description
search_yeast Search yeast strains by name, producer, type, attenuation range
search_styles Search BJCP beer styles with vital statistics
search_hop_varieties Search hop varieties by name, purpose, alpha acid
search_fermentables Search grains, sugars, and extracts
search_inventory_hops Check hop inventory levels
search_inventory_yeast Check yeast inventory with expiration
get_equipment Get your brewing equipment profiles
list_fermentations List active and recent fermentations
get_fermentation_status Get detailed status of a specific batch
get_fermentation_history Get historical readings and ML predictions
get_ambient_conditions Get current temperature and humidity
save_recipe Save a recipe to your library
fetch_url Fetch and read content from a URL
rename_chat Rename the current conversation thread
search_threads Search previous conversations for recipes and discussions

API Endpoints

Devices & Sensors

Endpoint Method Description
/api/devices GET/POST List or register devices
/api/devices/{id} GET/PUT/DELETE Device management
/api/devices/{id}/calibration GET/PUT Device calibration data
/api/tilts GET List all detected Tilts
/api/tilts/{id} GET/PUT Get or update Tilt
/api/tilts/{id}/readings GET Historical readings
/api/tilts/{id}/calibration GET/POST Calibration points

Data Ingestion

Endpoint Method Description
/api/ingest/generic POST Auto-detect device format
/api/ingest/ispindel POST iSpindel HTTP endpoint
/api/ingest/gravitymon POST GravityMon HTTP endpoint

Yeast Library

Endpoint Method Description
/api/yeast GET List yeast strains (supports filtering)
/api/yeast/{id} GET Get yeast strain details
/api/yeast/producers GET List all yeast producers
/api/yeast/refresh POST Refresh yeast database from seed file

Query Parameters for /api/yeast:

  • search - Full-text search on name and producer
  • producer - Filter by producer name
  • type - Filter by type (ale, lager, wild, hybrid)
  • form - Filter by form (dry, liquid)
  • flocculation - Filter by flocculation level
  • limit - Max results (default: 100)
  • offset - Pagination offset

Batches & Recipes

Endpoint Method Description
/api/batches GET/POST List or create batches
/api/batches/active GET List active batches
/api/batches/completed GET List completed batches
/api/batches/{id} GET/PUT Get or update batch
/api/batches/{id}/progress GET Detailed fermentation progress
/api/batches/{id}/delete POST Soft or hard delete batch
/api/batches/{id}/restore POST Restore soft-deleted batch
/api/recipes GET/POST List or create recipes (BeerJSON schema)
/api/recipes/{id} GET/PUT/DELETE Recipe with full ingredients (BeerJSON)
/api/recipes/import POST Import BeerXML, BeerJSON, or Brewfather JSON

Recipe Fields (BeerJSON 1.0):

  • Core: og, fg, ibu, abv, color_srm, batch_size_liters
  • Timing: boil_time_minutes, efficiency_percent, carbonation_vols
  • Extensions: format_extensions (preserves BeerXML/Brewfather metadata)
  • Relationships: fermentables, hops, cultures (yeasts), miscs, water profiles, mash steps, fermentation steps

Temperature Control

Endpoint Method Description
/api/control/status GET Global temperature control status (deprecated)
/api/control/batch/{id}/status GET Temperature control status for specific batch
/api/control/override POST Set manual heater/cooler override (requires batch_id and device_type)
/api/control/heater-entities GET List available HA heater entities
/api/control/cooler-entities GET List available HA cooler entities

Data Maintenance

Endpoint Method Description
/api/maintenance/orphaned-data GET Detect orphaned readings
/api/maintenance/cleanup-readings POST Preview/execute orphaned reading cleanup

System & Config

Endpoint Method Description
/api/config GET/PATCH Application settings (smoothing, units, etc.)
/api/system/info GET System information
/api/ambient GET Ambient temp/humidity from HA
/api/alerts GET Weather forecast and alerts
/ws WebSocket Real-time readings
/log.csv GET Export all data as CSV

Interactive API Documentation

Full API documentation with request/response examples available at:

  • Local: http://localhost:8080/docs
  • Raspberry Pi: http://<raspberry-pi-ip>:8080/docs

iSpindel/GravityMon Setup

Configure your iSpindel or GravityMon to POST to:

http://<raspberry-pi-ip>:8080/api/ingest/ispindel

The server auto-detects GravityMon extended format. Readings appear on the dashboard alongside Tilt devices.

BeerXML Import

Import a BeerXML file to auto-populate recipe targets and link batches:

curl -X POST "http://<raspberry-pi-ip>:8080/api/recipes/import" \
  -F "file=@/path/to/recipe.xml"

Imports include:

  • Recipe metadata (name, brewer, style, etc.)
  • Fermentables with weights and colors
  • Hops with timing and alpha acids
  • Yeast strains and attenuation
  • BJCP style guidelines (OG, FG, ABV, IBU ranges)

Calibration

Add calibration points to correct SG and temperature readings:

  1. Take a reference reading with a hydrometer/thermometer
  2. Note the raw value shown in BrewSignal
  3. Add a calibration point: raw value → actual value
  4. The system uses linear interpolation (Tilt) or polynomial fitting (iSpindel/GravityMon) between points

Development

# Backend (FastAPI)
cd brewsignal
pip install -e ".[dev]"
uvicorn backend.main:app --reload

# Frontend (Svelte)
cd frontend
npm install
npm run dev

Building Frontend

cd frontend
npm run build  # Outputs to backend/static/

Tech Stack

  • Backend: FastAPI, SQLAlchemy 2.0 (async), SQLite, Bleak (BLE)
  • Frontend: SvelteKit 2.x, Svelte 5, TailwindCSS v4, uPlot
  • Deployment: Systemd, uvicorn

Changelog

See CHANGELOG.md for detailed version history.

License

MIT

Acknowledgments