How to Control Your Inverter Fan Via PWM With an ESP32

by Jabrillo in Circuits > Arduino

2249 Views, 0 Favorites, 0 Comments

How to Control Your Inverter Fan Via PWM With an ESP32

IMG_20220622_144738.jpg

In this project, I will show you how I hacked my inverter to reduce the noise coming from the fans. Along the way, I will show you how to use a PWM signal coupled with a MOSFET to control the speed of any fan, and how to develop a webpage with your ESP32 to control the temperature and the speed. Let's get started!

Identifying the Problem

My inverter was not noisy in general, except for the moments in which the main fan kicked in: suddenly, a huge air movement could be heard from all over the house for a minute or so, before stopping itself just for a few minutes before starting the cycle again.

This happened because cheap inverters (like mine) do not provide fans with speed control. Instead, they spin them at max speed whenever the max temperature of the components is reached. This method is fairly simple, but it made even enjoying some TV annoying during the sunny hours when the inverter worked the most.

Of course, if your inverter is placed someplace far (not like mine which is basically in the living room), this guide won't be very useful to you. Nevertheless, I hope you will learn something new along the way, may it be regarding the ESP32 or may it be regarding some Python!

Disassembly of the Inverter

IMG_20220618_111356.jpg

The first step is to open the lid on your inverter (always BE CAREFUL and unplug it from both the AC line and the PV input, as well as shorting the capacitors that could store some leftover energy). Mine is a SUN-1000GTIL (bought on AliExpress for ~€250).

Then, you should find the fans. Mine has 2 weak fans on the outside and a stronger one inside next to the big heatsink. All three of them are 2-wire 12VDC fans, thus the only way of controlling their speed is through the use of a PWM signal and a MOSFET. You should be able to easily track their wires as they are thin red and black wires with usually a JST connector on the other end.

Buying the Parts

This project has been made using spare parts I had laying around, which were:

  • ESP32 (it's an overkill, and even an ESP8266 would have been fine)
  • Thermistor (B3950-10K 1% - a very common 10K NTC thermistor)
  • N-CHANNEL MOSFET (I used a IRFZ44N, but any N-CHANNEL is fine as the current going through it is less than 1A)
  • NPN (I used the very common 2N2222, but any model is fine)
  • Various resistors

Then, I added some optional components as I already had them, such as:

  • LED (a red one dimmed according to the fan speed)
  • Thermal switch (mine is a normally open switch which closes at 45°C)
  • Fuse (for the 12V input)
  • Capacitor

As power supply, I used an old 12V/1A wall adapter.

To power the ESP32 I stepped down the 12V to 5V using a buck converter.

Build the Circuit

Schematic_Fan inverter_2022-06-22.png
IMG_20220618_092355.jpg
IMG_20220618_092407.jpg
IMG_20220618_092530.jpg

Then, the juicy part: assembling the circuit board.

The schematic is fairly simple: the 12V from the wall adapter is fed via a screw terminal. A fuse is put in series for safety, but it is not needed. Then, a fairly big capacitor (100uF, 16V) is put between 12V and GND to improve the voltage stability and reduce the high-frequency noise that could come from the fans later. If you don't have these components, you can skip them with confidence.

The 12V gets converted to 5V using a buck converted, which is then fed to the VIN pin of the ESP32.

The thermistor is wired using a simple voltage divider using a 10k resistor.

The fans, as well as the LED (with a resistor in series to limit the current), are connected all in parallel and are switched by the N-CHANNEL MOSFET. In turn, the MOSFET is switched applying a PWM signal to the PNP.

The fans are wired through male header pins on the circuit board to match the female JST connectors in the inverter fans. I thought about wiring the fans in a separate way to allow control on each single fan, but these would have made things more complex and it was not worth the risk. Regardless, all the three fans made a similar noise so sharing the same PWM value would have been fine.

The thermal switch is wired through a screw terminal in parallel to the MOSFET. This allows the fans to work even if the ESP32 is dead whenever the temperature inside the inverter gets too high.

I've decided to split the boards into 2 parts: one containing the ESP32, the other one containing all the rest. They are connected using some off-the-shelf jumper wires. This allowed me to better fit the boards inside the inverter.

A detailed schematic in PDF format is below (higher resolution).

Code!

The code I used is fairly simple, and I commented the main parts. I also left some Serial.print to debug at the Serial console at 115200 baud rate.

To make it work, you just need to add your WiFi credentials on lines 35 (SSID) and 36 (password).

If you want to understand how it works, here is a general explanation:

  • Firstly, a server on port 80 (default) is created. This will allow us later to open the webpage at 192.168.1.xxx (at least, in my case it's like this) without needing to specify the port.
  • Then, the HTML page is created using some basic knowledge of HTML programming.
  • Through the webpage, we are able to input the main parameters:
  • Max temperature
  • Min temperature
  • Fan speed
  • Mode
  • The main parameters of the code are stored inside the ESP32 SPIFFS, which retains the values even when rebooted.
  • Depending on the mode and the current temperature read by the thermistor, the fans will spin at a certain percentage of their maximum speed.

In particular, the mode of operations are 2:

  • 1, Min-Max speed: this mode works by enabling the fans as soon as the temperature is above the minimum one. The starting minimum speed is the fan speed inputted before. This is because some fans won't start at too low PWM values. Then, if the temperature keeps rising, the fan speed will increase linearly until reaching 100% at max temperature.
  • 2, Hysteresis: this mode works similarly to a cooling thermostat: if the temperature rises above the max temperature, the fans start spinning at the inputted fan speed (constant value) until the temperature gets below the minimum temperature.

Regarding the temperature readings, I have implemented a lookup table to improve the accuracy and reliability of the thermistor as well as averaging the result over 100 samples taken in series.

The Arduino code is below. Remember when uploading it to the board, to select the correct ESP32 board (mine was the DEVKIT V1).

Put Everything Together!

IMG_20220618_101601.jpg
IMG_20220618_111403.jpg
IMG_20220622_144749.jpg
IMG_20220622_144758.jpg
IMG_20220622_145053.jpg
IMG_20220622_144837.jpg
IMG_20220622_145009.jpg
IMG_20220622_144959.jpg
IMG_20220622_144951.jpg
IMG_20220622_144926.jpg
IMG_20220622_144810.jpg

Here, I've uploaded as many photos as possible to show you how I positioned the 2 boards. I commented all of them to better explain what they show

Conveniently, the main heatsink at the centre of the inverter had a small hole where the thermistor head perfectly fitted inside. The fans are all wired using their original wires and connector, just being careful to put all of them with the right polarity.

About the rest, I just run the 12V input wires through an existing hole in the inverter enclosure, and tried to fit the 2 boards as snuggly as possible. Then, I secured everything with hot glue.

Make It Work!

Website.png

Now that everything has been put together, you can start testing the fans.

To find the IP of the ESP32, I recommend using the free software Advanced IP Scanner (https://www.advanced-ip-scanner.com/it/)

Then, you should see a webpage that looks like this. Here, you can input the values, then press submit. The page is not dynamic so to see any change, you have to reload it every time.

Now, have some fun!

If you want to take a look at how all of this works, take a look at this video: https://youtu.be/a2nEIo2IJSM

Log the Data

Python_screen.png

To choose the optimal mode of operation, as well as max temperature, min temperature and fan speed, I analysed the operating conditions for a few days.

This was done with a python code that reads the HTML code every 2s on the webpage and extracts the data. Then, it prints it out and saves it to a .txt file as log. The python code was run on my computer, but you can easily run it on a Raspberry Pi.

Here is the code:

import requests
import time
import threading
from csv import writer


url = "http://192.168.1.147/"
fileName = "log.txt"




def read_write_data():
    timestep = 2  # Seconds
    threading.Timer(timestep, read_write_data).start()
    html_content = requests.get(url).text
    inputMaxTemperature = html_content[496:498]
    inputMinTemperature = html_content[704:706]
    inputFanSpeed = html_content[907:909]
    inputMode = html_content[1132:1133]
    temperature = html_content[343:348]
    fanSpeed = html_content[367:369]
    info = [time.strftime('%Y-%m-%d %H:%M:%S'),
            inputMaxTemperature, inputMinTemperature, inputFanSpeed, inputMode, temperature, fanSpeed]
    print(info)
    append_list_as_row(fileName, info)




def append_list_as_row(file_name, list_of_elem):
    # Open file in append mode
    with open(file_name, 'a+', newline='') as write_obj:
        # Create a writer object from csv module
        csv_writer = writer(write_obj)
        # Add contents of list as last row in the csv file
        csv_writer.writerow(list_of_elem)




read_write_data()

The python file is also below.

Downloads

Check the Results!

log_plot_results.png

Then, the log was plotted using Matlab (but you can easily do it with python as well).

For some reason, I can't upload the Matlab code here, so I'm just gonna paste it here:

 %% CLEAR ALL
close all; clear; clc


%% IMPORT LOG DATA
% It will be read as a table with headers
log = readtable('log.txt');


%% PLOT
% Create a new figure 
figure()


% First subplot
ax1 = subplot(2, 1, 1);
hold on
grid on
legend
ylabel('°C')
% Plot temperature limits
plot(log.time, log.inputMinTemperature, ...
    '-.', 'DisplayName', 'Temperature - Minimum')
plot(log.time, log.inputMaxTemperature, ...
    '-.', 'DisplayName', 'Temperature - Maximum')
% Plot data points with color based on the fan speed
scatter(log.time, ... % x
    log.temperature, ... % y
    10, ... % size
    log.fanSpeed, ... % color
    "filled", ...
    'DisplayName', 'Temperature - Scatter')
c = colorbar; % Show colorbar
c.Label.String = 'Fan speed [%]';
% Plot also a line connecting all the scattered points
plot(log.time, log.temperature, 'DisplayName', 'Temperature - Line')


% Second subplot
ax2 = subplot(2, 1, 2);
hold on
grid on
legend
ylabel('°C/s')
% Plot the derivative of the temperature [°C/s], with color based on the
% fan speed
scatter(log.time(2:end), ... % x
    diff(log.temperature)./seconds(diff(log.time)), ... % y
    10, ... % size
    log.fanSpeed(2:end), ... % color
    "filled", ...
    'DisplayName', 'Temperature - Differential')
c = colorbar; % Show colorbar
c.Label.String = 'Fan speed [%]';
% Plot also a line connecting all the scattered points using a moving mean
% over 3 data points
plot(log.time(2:end), ... % x
    movmean(diff(log.temperature)./seconds(diff(log.time)), 3), ... % y
    'r--', ... % color & style
    'DisplayName', 'Temperature - Moving mean', ...
    LineWidth=2)


% Link x axes
linkaxes([ax1, ax2], 'x')

I've uploaded my log data as well so you can compare it to yours.

Furthermore, I've added a more detailed chart of the results I've got below, so you can better take a look at the various dynamics.