2025-07-09 22:55:35 -06:00
2025-07-08 18:26:54 -06:00
2025-07-09 11:18:55 -06:00
2025-07-09 10:00:05 -06:00

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.

Description
No description provided
Readme 200 KiB
Languages
C 99.6%
CMake 0.4%