Reviving LG fridge with custom PID control
i.e. controlling the Nidec BLDC Fan Motor with ESPHome
Identifying the part

The label reads Nidec Z40E12MS1A0-57K06, BLDC 1A DC12V, made in Vietnam. There’s also an EAU64843803 code, which is an LG appliance part number — a strong hint that no public datasheet exist.
The important detail is that it’s a BLDC with an integrated driver. Flipping the rotor off reveals a small PCB with a driver IC, a few passives, and a silkscreen legend that does all the documentation work for us:

FG
PWM
VBB
GND
Four pads, four wires. No external ESC required — feed it 12 V and a logic signal and it runs.
There’s also a pad marked CW near R2, which is a direction-select input.
Checking it before applying power
Salvaged electronics deserve a multimeter pass first. Measuring against GND:
| Pin | Reading | Meaning |
|---|---|---|
| VBB | ~26 kΩ | Leakage through the driver IC |
| PWM | ~9 kΩ | A real pull-down resistor. The input is biased, not floating. |
| FG | Open | Correct for an idle open-collector output with no pull-up. |
First power-up
Bench supply at 12.0 V with the current limit set to 0.4 A. VBB and GND only, PWM left floating.
Result: 20 mA and no rotation.
That’s not a failure — 20 mA is the driver IC’s quiescent draw. The chip is alive, it just isn’t commutating. Given the 9 kΩ pull-down, a floating PWM input reads as logic low, which means off.
Tying PWM to VBB spun it up immediately (using 1kΩ resistor). Non-inverted logic confirmed: high means run. The CW pad never needed touching, so its default floating state gives a valid direction.
A follow-up test showed 3.3 V is enough to trigger the input, while 12 V is clearly tolerated. That wide range means a microcontroller pin can drive it directly with no level shifting.
Characterising the interface
| Signal | Behaviour |
|---|---|
| VBB | 12 V, ~20 mA idle, 1 A is the stall/load rating |
| PWM | True duty-cycle input, ~25 kHz, non-inverted, 3.3 V logic sufficient, floating = off |
| FG | Open-collector tach, needs a pull-up, typically 3 pulses per revolution (unconfirmed) |
| CW | Direction select, safe to leave unconnected (unconfirmed; not expose over the wires) |
PWM here is a genuine square-wave duty input.
Why ESP32 and not ESP8266
The motor wants 25 kHz. esp8266_pwm is a software implementation and gets unreliable above roughly 1 kHz. The ESP32’s LEDC peripheral generates 25 kHz in hardware without touching the CPU.
Here’s a basic esphome script.
| ESP32-C3 Pin | Connects to | Notes |
|---|---|---|
| GPIO1 | Fan PWM control input | 25 kHz PWM, drives fan_pwm output |
| GPIO2 | Fan FG (tachometer) output | Open-collector — internal pull-up enabled in software |
| GPIO3 | DS18B20 data (DQ) | Needs an external ~4.7kΩ pull-up resistor to 3.3V |
| 3.3V | DS18B20 VDD, pull-up resistor | Normal (non-parasitic) power mode |
| GND | DS18B20 GND, fan signal GND | Common ground with the ESP32 |
| 12V supply (external, not ESP32) | Fan V+ | |
| 12V supply GND | Fan GND | Tie to common ground with ESP32/DS18B20 GND |
esphome:
name: fridge
esp32:
variant: esp32c3
framework:
type: esp-idf
logger:
level: DEBUG
hardware_uart: UART0
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# ---------------------------------------------------------------
# PWM output -> motor PWM pin
# 25 kHz matches the Nidec Z40E12MS1A0 input spec.
# 10-bit resolution is the practical ceiling at this frequency.
# ---------------------------------------------------------------
output:
- platform: ledc
id: fan_pwm
pin: GPIO1
frequency: 25000Hz
min_power: 15%
max_power: 100%
zero_means_zero: true
sensor:
- platform: pulse_counter
pin:
number: GPIO2
mode:
input: true
pullup: true
id: fan_tach
name: "Motor RPM"
unit_of_measurement: "RPM"
accuracy_decimals: 0
update_interval: 5s
count_mode:
rising_edge: DISABLE
falling_edge: INCREMENT
filters:
- multiply: 0.3333
- platform: dallas_temp
id: fridge_temperature
name: "Fridge Temperature"
update_interval: 30s
- platform: pid
name: "Motor Duty"
climate_id: fridge_climate
type: COOL
one_wire:
- platform: gpio
pin: GPIO3
climate:
- platform: pid
id: fridge_climate
name: "Fridge"
sensor: fridge_temperature
default_target_temperature: 4°C
cool_output: fan_pwm
control_parameters:
kp: 0.04
ki: 0.0015
kd: 0.0
visual:
min_temperature: -2 °C
max_temperature: 10 °C
temperature_step: 0.5 °C