I got a new router recently and, because it was running too hot, I decided to 3D print a stand with active cooling for it and to integrate it with Home Assistant.
Making the Stand



In order to make the stand, you’ll need to download the STL files from https://makerworld.com/en/models/2110927-router-dual-fan-stand and 3D print the required parts.
As well as the 3D printed parts, you’ll need the following:
- 2x 80mm fans
- Insect mesh, to try to reduce the amount of dust pushed towards the router
- 1x Adafruit HUZZAH32 – ESP32 Breakout Board ( for ESPHome)
- 1x MT3608 DC-DC
- 1x USB Type C 3.1 Female Socket DIY Serial Basic Breakout Female Connector
- 1x 10V, 470uF capacitor + 1x 16V, 470uF capacitor
- 1x A03400 mosfet for PWM control
Once you’ve printed the required parts, assemble them.







Building the controller



For the controller you’ll need to make the following connections.
- Connect the USB C PCB with the 10V, 470uF capacitor
- Power the ESP32 directly from the USB C using the V+ pin as that can take up to 6V
- Connect the USB C PCB with the VI+ and VI- on the MT3608 DC-DC
- Connect the VO+ and VO- with the 16V, 470uF capacitor
- Connecting the Fan
- VO+ with the fan V
- D(Drain) from the MOSFET with Fan GND
- Connecting the MOSFET
- ESP32 GPIO21 — Gate
- Gate — 100kΩ — GND (pulldown)
- MOSFET Source — GND (common with ESP32)
- MOSFET Drain — Fan(-)
ESPHome YAML Code
esphome:
name: router-fan
esp32:
board: featheresp32
framework:
type: esp-idf
logger:
api:
ota:
- platform: esphome
password: ""
wifi:
ssid: "WIFI_SSID"
password: "WIFI_PASSWORD"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Router Fan Control"
password: "SSID_PW"
# -------------------------------
# PWM OUTPUT (Fan Speed Control)
# -------------------------------
output:
- platform: ledc
pin: GPIO21
id: router_fan_pwm
frequency: 25000 Hz
# -------------------------------
# Home Assistant Fan Entity
# -------------------------------
fan:
- platform: speed
name: "Speed Control"
output: router_fan_pwm
speed_count: 100
id: router_fan
Sending the data from Flint 2 (GL-MT6000) to your Home Assistant
Required Libraries:
- mosquitto-client-nossl
- nano-full
Creating the required Files.
/usr/bin/mqtt_sensors.sh
#!/bin/sh
MQTT_HOST="192.168.8.123"
MQTT_PORT="1883"
MQTT_USER="mqtt_user"
MQTT_PASS="mqtt_passwrd"
DEVICE_ID="GL-MT6000"
INTERVAL=5
BASE_TOPIC="home/$DEVICE_ID"
DISCOVERY_PREFIX="homeassistant"
# ---------------- HELPERS ----------------
publish_discovery() {
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-t "$1" -r -m "$2"
}
publish_value() {
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-t "$1" -r -m "$2"
}
DEVICE_JSON="\"device\":{
\"identifiers\":[\"$DEVICE_ID\"],
\"name\":\"$DEVICE_ID\",
\"manufacturer\":\"GL.iNet\",
\"model\":\"GL-MT6000\"
}"
# ---------------- HA DISCOVERY ----------------
publish_discovery "$DISCOVERY_PREFIX/sensor/${DEVICE_ID}_temperature/config" "{
\"name\":\"CPU Temperature\",
\"state_topic\":\"$BASE_TOPIC/temperature\",
\"unit_of_measurement\":\"°C\",
\"device_class\":\"temperature\",
\"unique_id\":\"${DEVICE_ID}_temperature\",
$DEVICE_JSON
}"
publish_discovery "$DISCOVERY_PREFIX/sensor/${DEVICE_ID}_cpu/config" "{
\"name\":\"CPU Load\",
\"state_topic\":\"$BASE_TOPIC/cpu\",
\"unit_of_measurement\":\"%\",
\"icon\":\"mdi:cpu-64-bit\",
\"unique_id\":\"${DEVICE_ID}_cpu\",
$DEVICE_JSON
}"
publish_discovery "$DISCOVERY_PREFIX/sensor/${DEVICE_ID}_memory/config" "{
\"name\":\"Memory Usage\",
\"state_topic\":\"$BASE_TOPIC/memory\",
\"unit_of_measurement\":\"%\",
\"icon\":\"mdi:memory\",
\"unique_id\":\"${DEVICE_ID}_memory\",
$DEVICE_JSON
}"
# ---------------- MAIN LOOP ----------------
while true; do
# CPU Temperature
RAW_TEMP=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null)
[ -z "$RAW_TEMP" ] && RAW_TEMP=0
TEMP=$(awk "BEGIN {printf \"%.2f\", $RAW_TEMP/1000}")
# CPU Load (scaled by 65536)
LOAD=$(ubus call system info | jsonfilter -e '@.load[0]')
[ -z "$LOAD" ] && LOAD=0
CPU=$(awk "BEGIN {printf \"%.2f\", $LOAD/65536*100}")
# Memory %
MEM_TOTAL=$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null)
MEM_TOTAL=${MEM_TOTAL:-0}
MEM_AVAILABLE=$(awk '/MemAvailable/ {print $2}' /proc/meminfo 2>/dev/null)
MEM_AVAILABLE=${MEM_AVAILABLE:-0}
MEM_USED=$((MEM_TOTAL-MEM_AVAILABLE))
MEM_PERC=$(awk "BEGIN {printf \"%.2f\", $MEM_USED*100/$MEM_TOTAL}")
# ---------------- PUBLISH ----------------
publish_value "$BASE_TOPIC/temperature" "$TEMP"
publish_value "$BASE_TOPIC/cpu" "$CPU"
publish_value "$BASE_TOPIC/memory" "$MEM_PERC"
sleep "$INTERVAL"
done
Once you have the file, use the following command to make it executable.
chmod +x /usr/bin/mqtt_sensors.sh
Create an init.d script to make it run as a service
/etc/init.d/mqtt_sensors
#!/bin/sh /etc/rc.common
# This service will run the mqtt_sensors script
START=99
STOP=10
start() {
echo "Starting MQTT Sensors Service..."
/usr/bin/mqtt_sensors.sh &
# Save the PID of the script to a file so we can kill it later
echo $! > /var/run/mqtt_sensors.pid
}
stop() {
echo "Stopping MQTT Sensors Service..."
# Get the PID of the running process
PID=$(cat /var/run/mqtt_sensors.pid)
kill $PID
rm /var/run/mqtt_sensors.pid
}
restart() {
stop
start
}
# Ensure the service runs after reboot
boot() {
start
}
Once you have the file, use the following command to make it executable.
chmod +x /etc/init.d/mqtt_sensors
Commands:
# Enable the service to start at boot
/etc/init.d/mqtt_sensors enable
# Disable auto-start on boot
/etc/init.d/mqtt_sensors disable
# Start, stop, or restart the service
/etc/init.d/mqtt_sensors start
/etc/init.d/mqtt_sensors stop
/etc/init.d/mqtt_sensors restart
# Check the symbolic links in /etc/rc.d/
ls -l /etc/rc.d/ | grep mqtt_sensors
# Find the current PID
ps | grep mqtt_sensors | grep -v grep
# Get the current memory usage
cat /proc/PID_ID/status | grep -E 'VmRSS|VmSize'
Home Assistant Automation
- id: router_fan_linear_control
alias: Router Fan Linear Control
description: "Linear fan speed control based on CPU temperature"
trigger:
platform: state
entity_id: sensor.gl_mt6000_cpu_temperature
action:
service: fan.set_percentage
target:
entity_id: fan.router_fan_speed_control
data:
percentage: >
{% set temp = states('sensor.gl_mt6000_cpu_temperature')|float %}
{% set min_temp = 32 %}
{% set max_temp = 65 %}
{% set min_speed = 15 %}
{% set max_speed = 100 %}
{% if temp <= min_temp %}
{{ min_speed }}
{% elif temp >= max_temp %}
{{ max_speed }}
{% else %}
{{ (min_speed + (temp - min_temp)*(max_speed - min_speed)/(max_temp - min_temp)) | round(0) }}
{% endif %}