Files
maxxfan-controller/README.md

12 KiB

Maxxfan Smart Controller

A WiFi-enabled smart controller for the Maxxfan Deluxe 6401K using ESP32 and BTS7960 motor driver. Transform your manual RV fan into a remotely controllable smart device with variable speed control, bidirectional operation, and smooth motor ramping.

🌟 Features

  • WiFi Remote Control - Control your fan from anywhere on your network
  • Variable Speed Control - 0-100% speed adjustment via web interface
  • Bidirectional Operation - Switch between exhaust and intake modes
  • Smooth Motor Ramping - Gradual speed changes prevent mechanical stress
  • Real-time Status - Live updates of fan mode, current speed, and target speed
  • Ramping Visualization - See when speed changes are in progress
  • Mobile-Friendly Interface - Responsive web design works on phones and tablets
  • Enhanced Error Handling - Visual connection status and error messages
  • CORS Support - Cross-origin requests properly handled
  • Compact Design - Optimized for ESP32 memory constraints
  • Connection Status - Shows "Connected", "Connecting", or "Error" status
  • REST API - Enhanced JSON API for integration with home automation systems
  • Watchdog Protection - Automatic system recovery from crashes
  • Homebridge Compatible - Easy integration with HomeKit

🔧 Hardware Requirements

Main Components

  • ESP32 Development Board (tested with SparkFun ESP32 Thing Plus)
  • BTS7960 Motor Driver Module (43A high-power motor driver)
  • Maxxfan Deluxe 6401K (or compatible 12V DC fan)
  • 12V Power Supply (adequate for your fan's current draw)

Wiring Connections

ESP32 GPIO → BTS7960 Pin
GPIO 18    → R_EN (Right Enable)
GPIO 19    → L_EN (Left Enable) 
GPIO 21    → R_PWM (Right PWM)
GPIO 22    → L_PWM (Left PWM)
GPIO 13    → LED (Status Indicator)
3.3V       → VCC (Logic Power)
GND        → GND

BTS7960 → Fan Motor
B+         → Fan Positive
B-         → Fan Negative

Power Supply
12V        → BTS7960 Motor Power + Fan Power Input
GND        → Common Ground

🚀 Quick Start

Prerequisites

  • Docker installed on Ubuntu (recommended) or Mac
  • ESP32 connected via USB
  • WiFi network credentials

1. Set Up Development Environment

# Create project directory
mkdir ~/maxxfan-controller
cd ~/maxxfan-controller

# Pull official ESP-IDF Docker image (v5.x recommended)
docker pull espressif/idf:latest

# Create new ESP-IDF project
docker run --rm -v $PWD:/project -w /project -it espressif/idf:latest
idf.py create-project maxxfan-controller
exit

2. Configure WiFi Credentials

Edit the WiFi credentials in main/maxxfan-controller.c:

#define WIFI_SSID "YOUR_WIFI_NAME"
#define WIFI_PASS "YOUR_WIFI_PASSWORD"

3. Build and Flash

cd maxxfan-controller

# Build
docker run --rm -v $PWD:/project -w /project -it espressif/idf:latest idf.py build

# Flash (replace /dev/ttyUSB0 with your device)
docker run --rm -v $PWD:/project -w /project --device=/dev/ttyUSB0 -it espressif/idf:latest idf.py flash -p /dev/ttyUSB0

# Monitor serial output
docker run --rm -v $PWD:/project -w /project --device=/dev/ttyUSB0 -it espressif/idf:latest idf.py monitor -p /dev/ttyUSB0

4. Access Web Interface

  1. Note the IP address from serial monitor output:

    I (xxx) HTTP_MOTOR: got ip:192.168.1.123
    
  2. Open your browser and navigate to: http://192.168.1.123

🌐 Enhanced Web Interface

The improved web interface provides:

  • Real-time Status Display - Current fan mode, speed, and target speed
  • Ramping Indicator - Visual feedback when speed changes are in progress
  • Quick Controls - One-click buttons for common operations
  • Speed Slider - Precise speed adjustment (0-100%)
  • Real-time Updates - Status refreshes every 1 second for live ramping visualization
  • Error Handling - Visual connection status and network error feedback
  • Persistent State - Settings maintained across page reloads
  • Memory Optimized - Compact HTML (~2KB) ensures reliable loading

Controls Available

  • Turn OFF - Stops the fan completely
  • Exhaust (50%) - Sets exhaust mode at 50% speed with smooth ramping
  • Intake (50%) - Sets intake mode at 50% speed with smooth ramping
  • Custom Speed - Use slider + "Set Exhaust/Intake Speed" buttons

Motor Ramping Features

  • Smooth Startup - Motors start at minimum speed (10%) then ramp to target
  • Gradual Changes - Speed changes in 5% increments every 50ms
  • Direction Changes - Proper sequencing prevents mechanical stress
  • Visual Feedback - Ramping indicator shows when changes are in progress

📡 Enhanced REST API

Get Status

GET /status

Enhanced Response:

{
  "mode": "exhaust",
  "current_speed": 65,
  "target_speed": 80,
  "ramping": true
}

Control Fan

POST /fan
Content-Type: application/json

{
  "mode": "exhaust",  // "off", "exhaust", or "intake"
  "speed": 75         // 0-100
}

Example cURL Commands

# Turn fan off (immediate stop)
curl -X POST http://192.168.1.123/fan -H "Content-Type: application/json" -d '{"mode":"off","speed":0}'

# Set exhaust mode at 80% (with ramping)
curl -X POST http://192.168.1.123/fan -H "Content-Type: application/json" -d '{"mode":"exhaust","speed":80}'

# Set intake mode at 60% (with ramping)
curl -X POST http://192.168.1.123/fan -H "Content-Type: application/json" -d '{"mode":"intake","speed":60}'

# Get current status (includes ramping state)
curl http://192.168.1.123/status

🏠 Homebridge Integration

Add to your Homebridge config.json:

{
  "accessories": [
    {
      "accessory": "HTTP-FAN",
      "name": "Maxxfan",
      "getUrl": "http://192.168.1.123/status",
      "setUrl": "http://192.168.1.123/fan",
      "on": {
        "setOn": "http://192.168.1.123/fan",
        "setOff": "http://192.168.1.123/fan"
      },
      "speed": {
        "setSpeed": "http://192.168.1.123/fan"
      }
    },
    {
      "accessory": "HTTP-SWITCH",
      "name": "Maxxfan Direction",
      "getUrl": "http://192.168.1.123/status",
      "setUrl": "http://192.168.1.123/fan",
      "mapOn": "intake",
      "mapOff": "exhaust"
    }
  ]
}

Requires: npm install -g homebridge-http-accessory

🔧 Technical Details

Enhanced Motor Control Logic

The BTS7960 is a dual H-bridge motor driver with improved control sequencing:

  • Exhaust Mode: R_EN=HIGH, L_EN=LOW, PWM on R_PWM pin
  • Intake Mode: R_EN=LOW, L_EN=HIGH, PWM on L_PWM pin
  • Off Mode: Both enables LOW, PWM stopped
  • Ramping: Gradual speed changes using FreeRTOS timers

Motor Ramping Configuration

#define RAMP_STEP_MS 50          // Time between ramp steps (50ms)
#define RAMP_STEP_SIZE 5         // PWM duty change per step (~2% speed)
#define MIN_MOTOR_SPEED 10       // Minimum speed to overcome inertia

PWM Configuration

  • Frequency: 1kHz (optimal for motor control)
  • Resolution: 8-bit (256 levels of speed control)
  • Speed Range: 0-100% mapped to 0-255 PWM duty cycle

Memory Optimization

The web interface HTML has been optimized to ~2KB (down from ~8KB) to ensure:

  • Complete page loading without truncation
  • Reliable JavaScript execution
  • Proper function definitions and event handling
  • Stable operation on ESP32's limited memory

Safety & Reliability Features

  • Watchdog Timer: Automatic system recovery from crashes
  • Enable Sequencing: Enable pins activated before PWM signals
  • Direction Switching: Proper delays prevent shoot-through current
  • Error Handling: Robust JSON parsing and HTTP error responses
  • CORS Headers: Cross-origin support for web integrations
  • Compact HTML: Optimized web interface for ESP32 memory constraints
  • Real-time Updates: 1-second polling for live status updates
  • Visual Feedback: Connection status and ramping progress indicators

🛠️ Development

Project Structure

maxxfan-controller/
├── main/
│   ├── maxxfan-controller.c    # Enhanced application code
│   └── CMakeLists.txt          # Build configuration
├── CMakeLists.txt              # Project configuration
└── sdkconfig                   # ESP-IDF configuration

Key Components

  • GPIO Control: Direct hardware pin management
  • LEDC PWM: Hardware PWM generation for speed control
  • FreeRTOS Timers: Motor ramping control
  • Task Watchdog: System reliability monitoring
  • WiFi Station: Connect to existing network
  • HTTP Server: Built-in ESP-IDF web server with CORS support
  • JSON Parsing: cJSON library for enhanced API requests

Building from Source

The project uses ESP-IDF v5.x with these main dependencies:

  • driver/gpio.h - GPIO control
  • driver/ledc.h - PWM generation
  • esp_http_server.h - Web server
  • esp_task_wdt.h - Watchdog timer
  • freertos/timers.h - Motor ramping timers
  • cJSON.h - JSON parsing
  • esp_wifi.h - WiFi connectivity

📋 Troubleshooting

Common Boot Messages (Normal)

W (501) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k)

This warning is normal - your ESP32 has more flash than the project uses.

WiFi Connection Issues

  • Verify SSID and password in code
  • Check 2.4GHz network (ESP32 doesn't support 5GHz)
  • Monitor serial output for connection status

Motor Not Responding

  • Check all wiring connections
  • Verify 12V power supply to BTS7960
  • Ensure common ground between ESP32 and motor circuit
  • Test with multimeter on enable pins (should show 3.3V when active)
  • Check for ramping messages in serial output

Web Interface Issues

  • Confirm IP address from serial monitor
  • Check browser developer console (F12) for JavaScript errors
  • Look for CORS or network errors
  • Try different browser or incognito mode

JavaScript Console Errors

If you see "Unexpected end of script" or "Can't find variable" errors:

  • These indicate HTML truncation due to memory constraints
  • The current compact HTML should resolve these issues
  • Check browser developer console (F12) for specific errors
  • Verify complete page load by viewing page source
  • If errors persist, try clearing browser cache and refreshing

Connection Status Issues

If the web interface shows "Connection Error":

  • Check that ESP32 is connected to WiFi (serial monitor should show IP)
  • Verify you're accessing the correct IP address
  • Check that both devices are on the same network
  • Try accessing /status endpoint directly: http://[ESP32_IP]/status
  • Look for CORS-related errors in browser console

Watchdog Timer Messages

If you see watchdog errors, check:

  • Main loop is running (should see periodic status updates)
  • No infinite loops in code
  • Adequate task stack sizes

Serial Port Issues (Ubuntu)

# Add user to dialout group
sudo usermod -a -G dialout $USER

# Check available ports
ls /dev/tty* | grep -E "(USB|ACM)"

# Fix permissions if needed
sudo chmod 666 /dev/ttyUSB0

Flash Size Warning Fix (Optional)

To use full 16MB flash and eliminate warning:

idf.py menuconfig
# Navigate to: Serial flasher config → Flash size → 16MB

🔒 Security Considerations

Current Implementation

  • Open Access: No authentication required
  • Local Network Only: Not accessible from internet
  • HTTP Only: Unencrypted communication
  • CORS Enabled: Allows cross-origin requests
  • Network Isolation: Use dedicated IoT VLAN
  • Basic Authentication: Add username/password protection
  • HTTPS: Enable SSL/TLS encryption
  • Firewall Rules: Restrict access to specific devices

📄 License

This project is open source. Use at your own risk. Always follow electrical safety practices when working with 12V systems.

🤝 Contributing

Feel free to submit issues, feature requests, or pull requests to improve this project.

⚠️ Disclaimer

This project involves working with electrical systems and motor control. Always:

  • Follow proper electrical safety practices
  • Use appropriate fuses and circuit protection
  • Test thoroughly before permanent installation
  • Ensure adequate ventilation and mounting
  • Check local electrical codes and regulations

The authors are not responsible for any damage or injury resulting from the use of this project.