Skip to content

remiserriere/google-home-notifier-python

 
 

Repository files navigation

Google Home Notifier Python

A modern, production-ready Python Flask web service for sending text-to-speech notifications and playing audio files on Google Home, Chromecast, and Chromecast Audio devices.

Note: This project is based on harperreed/google-home-notifier-python but has been extensively modernized and enhanced with production features including Kubernetes support, configurable volume control, improved network detection, and robust error handling.

Features

  • 🔊 Text-to-Speech (TTS) - Convert text to speech using Google's TTS service
  • 🎵 Audio Playback - Play MP3 files from local storage or external URLs
  • 🎛️ Configurable Volume - Set custom volume levels for different environments
  • 🔍 Auto-Discovery - Automatically find and connect to Chromecast devices
  • 📡 Direct IP Connection - Connect to specific Chromecast IP addresses
  • 🌐 Network Detection - Intelligent network IP detection for containerized environments
  • 📦 Production Ready - Docker and Kubernetes deployment configurations
  • 💾 TTS Caching - Cache generated audio files for faster playback
  • 🔄 Background Discovery - Continuous device discovery with reconnection support
  • 🧪 Test Endpoints - Built-in testing and debugging endpoints

Quick Start

Installation

  1. Clone the repository

    git clone https://github.com/your-username/google-home-notifier-python.git
    cd google-home-notifier-python
  2. Install dependencies

    pip install -r requirements.txt
  3. Configure environment variables

    cp .env.example .env
    # Edit .env with your Chromecast settings
  4. Run the service

    python main.py

The service will start on http://localhost:5000

Basic Usage

Text-to-Speech

# Basic TTS in English
curl "http://localhost:5000/say/?text=Hello World"

# TTS in different languages
curl "http://localhost:5000/say/?text=Bonjour le monde&lang=fr"
curl "http://localhost:5000/say/?text=こんにちは世界&lang=ja"

Audio Playback

# Play a local MP3 file
curl "http://localhost:5000/play/doorbell.mp3"

Configuration

Environment Variables

Create a .env file in the project root with the following configuration:

# Chromecast Configuration
# Set the exact name of your Chromecast device (optional)
GRP_NAME="Living Room speaker"

# Set the IP address of your Chromecast if discovery fails (recommended)
CHROMECAST_IP=192.168.1.100

# External host/IP for Chromecast to access files (useful for K8s, Docker, etc.)
# Examples:
# EXTERNAL_HOST=192.168.1.100        # Local network IP
# EXTERNAL_HOST=myapp.mydomain.com    # Domain name
# EXTERNAL_HOST=10.43.0.15           # K8s service IP
# EXTERNAL_HOST=                     # Leave empty for auto-detection
EXTERNAL_HOST=

# Volume level for playback (0.0 to 1.0, where 1.0 is maximum)
# Examples: 0.3 = 30% (office), 0.6 = 60% (home), 1.0 = 100% (demos)
PLAYBACK_VOLUME=0.6

# Discovery settings (optional)
DISCOVERY_RETRY_SEC=10
DISCOVERY_WAIT_TIMEOUT=30
PLAYBACK_TIMEOUT=300

Configuration Examples by Environment

Home Environment

CHROMECAST_IP=192.168.1.100
EXTERNAL_HOST=192.168.1.50
PLAYBACK_VOLUME=0.6

Office Environment

CHROMECAST_IP=10.0.1.100
EXTERNAL_HOST=10.0.1.50
PLAYBACK_VOLUME=0.3

Public Demo Environment

CHROMECAST_IP=172.16.1.100
EXTERNAL_HOST=172.16.1.50
PLAYBOOK_VOLUME=1.0

API Endpoints

Core Endpoints

GET /say/

Convert text to speech and play on Chromecast.

Parameters:

  • text (required) - Text to convert to speech
  • lang (optional) - Language code (default: "en")

Examples:

curl "http://localhost:5000/say/?text=Hello World"
curl "http://localhost:5000/say/?text=Bonjour&lang=fr"

GET /play/{filename}

Play an MP3 file from the static directory.

Parameters:

  • filename - Name of the MP3 file in the static directory

Example:

curl "http://localhost:5000/play/notification.mp3"

Discovery and Management Endpoints

GET|POST /discover/status

Check current Chromecast discovery status.

Response:

{
  "cast_found": true,
  "target_name": "Living Room speaker",
  "chromecast_ip": "192.168.1.100",
  "cast_name": "Living Room speaker"
}

GET|POST /discover/restart

Force restart of the discovery process.

GET|POST /discover/reconnect

Force reconnection to the Chromecast device.

GET /discover/debug

Get detailed debugging information about the current Chromecast connection.

GET /discover/test

Perform manual discovery test and return debugging information.

Test Endpoints

GET /test/external

Test playback with an external audio file.

GET /test/local-ip

Test playback using local network IP instead of localhost.

GET /test/audio-formats

Test different audio format compatibility.

GET /test/volume

Test and adjust Chromecast volume.

GET /test/mp3

Direct MP3 playback test.

Core Functions

Discovery Functions

start_background_discovery()

Starts the background discovery thread for automatic Chromecast detection.

_discover_loop(name: str, retry_interval: int)

Main discovery loop that runs in a background thread. Handles both direct IP connection and network discovery.

_get_cast(timeout: Optional[float]) -> Optional[pychromecast.Chromecast]

Returns the discovered Chromecast device, waiting up to timeout seconds if needed.

Audio Functions

play_tts(text: str, lang: str = "en", slow: bool = False)

Generates TTS audio file (or uses cached version) and plays it on the Chromecast.

Parameters:

  • text - Text to convert to speech
  • lang - Language code (ISO 639-1)
  • slow - Whether to use slow speech rate

play_mp3(mp3_url: str, playback_timeout: int = PLAYBACK_TIMEOUT)

Plays an MP3 URL on the Chromecast with configurable volume and automatic volume restoration.

Parameters:

  • mp3_url - URL of the MP3 file to play
  • playback_timeout - Maximum time to wait for playback completion

Utility Functions

_get_accessible_host_url(request) -> str

Intelligently determines the best host URL for Chromecast to access files.

Priority order:

  1. EXTERNAL_HOST environment variable
  2. Auto-detected network IP
  3. Request URL with localhost replacement

_tts_filename(text: str, lang: str, slow: bool) -> str

Generates a stable, unique filename for TTS cache files.

restart_discovery() -> dict

Stops current discovery and starts a fresh discovery process.

Docker Deployment

Docker Compose

Create a docker-compose.yml file:

version: '3.8'
services:
  google-home-notifier:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: google-home-notifier
    restart: unless-stopped
    network_mode: host
    environment:
      - CHROMECAST_IP=192.168.1.100
      - EXTERNAL_HOST=192.168.1.50
      - PLAYBACK_VOLUME=0.6
      - GRP_NAME=Living Room speaker
    ports:
      - "5000:5000"
    volumes:
      - ./static:/app/static

For production/secure deployments, use:

# Secure version with localhost-only binding
docker-compose -f docker-compose.secure.yml up -d

See docker-compose.secure.yml for security-hardened configuration.

Updated Dockerfile

FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Create static directory for cache
RUN mkdir -p static/cache

# Environment variables with defaults
ENV CHROMECAST_IP=""
ENV EXTERNAL_HOST=""
ENV PLAYBACK_VOLUME=0.6
ENV GRP_NAME="Google Home"
ENV DISCOVERY_RETRY_SEC=10
ENV DISCOVERY_WAIT_TIMEOUT=30
ENV PLAYBACK_TIMEOUT=300

# Expose port
EXPOSE 5000

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5000/discover/status || exit 1

# Run application
CMD ["python", "main.py"]

Run with Docker

# Build the image
docker build -t google-home-notifier .

# Run the container
docker run -d \
  --name google-home-notifier \
  --network host \
  -e CHROMECAST_IP=192.168.1.100 \
  -e EXTERNAL_HOST=192.168.1.50 \
  -e PLAYBACK_VOLUME=0.6 \
  -p 5000:5000 \
  google-home-notifier

# Run with Docker Compose
docker-compose up -d

Security Best Practices

🔒 Network Security:

  • Bind to specific interfaces: -p 127.0.0.1:5000:5000 (localhost only)
  • Use firewall rules to restrict access
  • Consider VPN access for remote control

🔐 Authentication Options:

  • Add reverse proxy with authentication (nginx, Traefik)
  • Use API keys or tokens
  • Implement IP whitelisting

🛡️ Production Deployment:

# Secure local-only binding
docker run -d \
  --name google-home-notifier \
  -p 127.0.0.1:5000:5000 \
  -e CHROMECAST_IP=192.168.1.100 \
  -e EXTERNAL_HOST=192.168.1.50 \
  google-home-notifier

Kubernetes Deployment

Deployment YAML

Create a k8s-deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: google-home-notifier
  labels:
    app: google-home-notifier
spec:
  replicas: 1
  selector:
    matchLabels:
      app: google-home-notifier
  template:
    metadata:
      labels:
        app: google-home-notifier
    spec:
      # hostNetwork: true  # Option 1: Required ONLY for automatic Chromecast discovery
      # Alternative: Use specific IPs instead (more secure)
      containers:
      - name: google-home-notifier
        image: google-home-notifier:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5000
        env:
        # Method 1: Direct IP configuration (recommended for K8s)
        - name: CHROMECAST_IP
          value: "192.168.1.100"  # Your Chromecast IP
        - name: EXTERNAL_HOST
          value: "192.168.1.50"   # Your K8s node IP or service IP
        # Method 2: For auto-discovery, uncomment hostNetwork above and remove CHROMECAST_IP
        - name: PLAYBACK_VOLUME
          value: "0.6"
        - name: GRP_NAME
          value: "Living Room speaker"
        livenessProbe:
          httpGet:
            path: /discover/status
            port: 5000
          initialDelaySeconds: 30
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /discover/status
            port: 5000
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        volumeMounts:
        - name: cache-volume
          mountPath: /app/static/cache
      volumes:
      - name: cache-volume
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: google-home-notifier-service
spec:
  type: NodePort
  selector:
    app: google-home-notifier
  ports:
  - port: 5000
    targetPort: 5000
    nodePort: 30500

Network Configuration Options

Option 1: Direct IP Configuration (Recommended)

  • Set CHROMECAST_IP to your Chromecast's IP address
  • Set EXTERNAL_HOST to your Kubernetes node IP
  • No hostNetwork: true needed
  • More secure and predictable

Option 2: Auto-Discovery Mode

  • Enable hostNetwork: true in the pod spec
  • Remove CHROMECAST_IP environment variable
  • Service will automatically discover Chromecast devices
  • Less secure but more flexible

ConfigMap for Environment Variables

Create a k8s-configmap.yaml file:

apiVersion: v1
kind: ConfigMap
metadata:
  name: google-home-notifier-config
data:
  CHROMECAST_IP: "192.168.1.100"
  EXTERNAL_HOST: "192.168.1.50"
  PLAYBACK_VOLUME: "0.6"
  GRP_NAME: "Living Room speaker"
  DISCOVERY_RETRY_SEC: "10"
  DISCOVERY_WAIT_TIMEOUT: "30"
  PLAYBACK_TIMEOUT: "300"

Then reference the ConfigMap in your deployment:

        envFrom:
        - configMapRef:
            name: google-home-notifier-config

Deploy to Kubernetes

# Create namespace (optional)
kubectl create namespace home-automation

# Apply ConfigMap
kubectl apply -f k8s-configmap.yaml -n home-automation

# Apply Deployment
kubectl apply -f k8s-deployment.yaml -n home-automation

# Check status
kubectl get pods -n home-automation
kubectl logs -f deployment/google-home-notifier -n home-automation

# Test the service
kubectl port-forward service/google-home-notifier-service 5000:5000 -n home-automation

For production/secure deployments:

# Use the security-hardened configuration
kubectl apply -f k8s-secure-deployment.yaml

See k8s-secure-deployment.yaml for security-hardened Kubernetes deployment with:

  • No hostNetwork requirement
  • Security contexts and non-root user
  • Resource limits and network policies
  • ClusterIP service (internal access only)

Security Considerations

⚠️ Important Security Notes:

  • No Authentication: This service has no built-in authentication
  • Public Exposure: Never expose this service directly to the internet without proper security measures
  • Internal Use Only: Recommended for internal networks or behind VPN/firewall
  • Alternative Access: Use kubectl port-forward or VPN for external access

If you need external access, consider:

  • Adding authentication (API keys, OAuth, etc.)
  • Using VPN or private network access
  • Implementing rate limiting
  • Adding input validation and sanitization

Troubleshooting

Common Issues

1. Chromecast Not Found

  • Verify the Chromecast IP address: CHROMECAST_IP=192.168.1.100
  • Check network connectivity: ping 192.168.1.100
  • Ensure devices are on the same network
  • Try the discovery test: curl http://localhost:5000/discover/test

2. No Audio Output

  • Check volume levels: curl http://localhost:5000/test/volume
  • Test with external audio: curl http://localhost:5000/test/external
  • Verify network accessibility from Chromecast to the service
  • Check firewall settings (Windows: allow port 5000)

3. Network Connectivity Issues

  • Use EXTERNAL_HOST for containerized environments
  • For Docker: set EXTERNAL_HOST to the host machine's IP
  • For Kubernetes: set EXTERNAL_HOST to the node IP
  • Test local IP detection: curl http://localhost:5000/test/local-ip

4. Docker/Kubernetes Issues

  • Use hostNetwork: true in Kubernetes for Chromecast discovery
  • Ensure proper volume mounts for TTS cache
  • Set appropriate resource limits
  • Check pod logs: kubectl logs -f pod-name

Debug Endpoints

Use these endpoints to diagnose issues:

# Check discovery status
curl http://localhost:5000/discover/status

# Get detailed debug info
curl http://localhost:5000/discover/debug

# Test discovery manually
curl http://localhost:5000/discover/test

# Test different audio formats
curl http://localhost:5000/test/audio-formats

# Test volume control
curl http://localhost:5000/test/volume

Firewall Configuration

Windows

# Allow inbound connections on port 5000
New-NetFirewallRule -DisplayName "Google Home Notifier" -Direction Inbound -Protocol TCP -LocalPort 5000 -Action Allow

Linux (UFW)

sudo ufw allow 5000/tcp

Linux (iptables)

sudo iptables -A INPUT -p tcp --dport 5000 -j ACCEPT

Development

Running in Development Mode

# Install dependencies
pip install -r requirements.txt

# Set environment variables
export CHROMECAST_IP=192.168.1.100
export PLAYBACK_VOLUME=0.6

# Run in debug mode
python main.py

Adding New Features

The application is structured with clear separation of concerns:

  • Discovery: Background thread for device discovery
  • Audio: TTS generation and playback functions
  • Network: Intelligent host detection for different environments
  • API: Flask routes for HTTP endpoints

Testing

Test the application using the built-in test endpoints:

# Test TTS functionality
curl "http://localhost:5000/say/?text=Testing"

# Test MP3 playback
curl "http://localhost:5000/test/mp3"

# Test volume control
curl "http://localhost:5000/test/volume"

# Test network connectivity
curl "http://localhost:5000/test/local-ip"

License

This project is based on harperreed/google-home-notifier-python and maintains the same open-source spirit.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues and questions:

  1. Check the troubleshooting section
  2. Use the debug endpoints to gather information
  3. Open an issue with detailed information about your environment

About

A google home notification webservice

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Python 71.2%
  • PowerShell 14.3%
  • Shell 12.2%
  • Dockerfile 2.3%