Reviewed-on: #13
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
-
Note the IP address from serial monitor output:
I (xxx) HTTP_MOTOR: got ip:192.168.1.123 -
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 controldriver/ledc.h- PWM generationesp_http_server.h- Web serveresp_task_wdt.h- Watchdog timerfreertos/timers.h- Motor ramping timerscJSON.h- JSON parsingesp_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
/statusendpoint 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
Recommended Improvements for Production
- 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.