Closed dartfrogdk closed 2 years ago
I was working on the electrical setup of my own implementation of this this weekend and ran into the same problem, apparently some fans are just set up this way. You have to use a relay to switch off the power entirely to the fan. I needed a level shifter as well to both up the PWM signal and the relay control signal to 5v. The next hurdle was that the fan then would run purely from the pwm output, so I also needed to switch off the level shifter output, luckily my level shifter allowed for control there too.
The end result (just for the fan for now, no PID control yet) looks as follows in the yam. GPIO27 switches off the relay (via the lvl shifter) and GPIO14 is the PWM signal itself (also via the lvl shifter). GPIO26 enables the lvl shifter for the pwm output, so switching that off blocks the pwm entirely (doing that without the relay will just run the fan at full speed sadly):
output:
- platform: gpio
pin: GPIO26
id: pwm_on
inverted: true
- platform: gpio
pin: GPIO27
id: fan_supply
- platform: ledc
pin: GPIO14
frequency: 25000 Hz
id: testfan
fan:
- platform: speed
output: testfan
name: "Test Fan"
on_turn_on:
- output.turn_on: fan_supply
- logger.log: "Power of Fan turned ON"
- output.turn_on: pwm_on
- logger.log: "PWM enabled"
on_turn_off:
- output.turn_off: fan_supply
- logger.log: "Power of Fan turned OFF"
- output.turn_off: pwm_on
- logger.log: "PWM disabled"
With this the fan switches off at 0. 1% is then the startup RPM of my fan.
okay thanks i will try this way
Hi everyone. My fan is wont stop. I tried to edit the code but I couldn't. can you help me?
substitutions:
friendly_name: Console Fan
esphome:
name: console-fan
# Throttle writing parameters to the internal flash memory to reduce ESP memory wear / degradation
preferences:
flash_write_interval: 120min
esp8266:
board: esp01_1m
# pid climate log update is noisy, dial it back to warn
logger:
level: DEBUG
logs:
climate: ERROR
dht: WARN
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
password: ""
wifi:
ssid:
password:
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Inverter-Fan Fallback Hotspot"
password: ""
captive_portal:
number:
## OPTIONAL:
# RECEIVE KP, KI and KD parameters from input_text.kx helpers in
# Home Assistant. See the PID controller below
# These helper values will get saved to flash thus permanently over-riding
# the initial values set in the PID below.
# KP
- platform: template
name: kp
icon: mdi:chart-bell-curve
restore_value: true
initial_value: 0.3
min_value: 0
max_value: 50
step: 0.001
set_action:
lambda: |-
id(console_thermostat).set_kp( x );
# KI
- platform: template
name: ki
icon: mdi:chart-bell-curve
restore_value: true
initial_value: 0.0015
min_value: 0
max_value: 50
step: 0.0001
set_action:
lambda: id(console_thermostat).set_ki( x );
# KD
- platform: template
name: kd
icon: mdi:chart-bell-curve
restore_value: true
initial_value: 0.0
min_value: -50
max_value: 50
step: 0.001
set_action:
lambda: id(console_thermostat).set_kd( x );
# Set threshold low
- platform: template
name: Deadband Threshold Low
icon: mdi:chart-bell-curve
restore_value: true
initial_value: -1.0
min_value: -20
max_value: 0
step: 0.1
set_action:
lambda: id(console_thermostat).set_threshold_low( x );
# Set threshold high
- platform: template
name: Deadband Threshold High
icon: mdi:chart-bell-curve
restore_value: true
initial_value: 0.4
min_value: 0
max_value: 20
step: 0.1
set_action:
lambda: id(console_thermostat).set_threshold_high( x );
# Set ki multiplier
- platform: template
name: Deadband ki Multiplier
icon: mdi:chart-bell-curve
restore_value: true
initial_value: 0.04
min_value: 0
max_value: .2
step: 0.01
set_action:
lambda: id(console_thermostat).set_ki_multiplier( x );
text_sensor:
# Send IP Address
- platform: wifi_info
ip_address:
name: $friendly_name IP Address
# Send Uptime in raw seconds
- platform: template
name: $friendly_name Uptime
id: uptime_human
icon: mdi:clock-start
sensor:
# Send WiFi signal strength & uptime to HA
- platform: wifi_signal
name: $friendly_name WiFi Strength
update_interval: 60s
# This is a bit of overkill. It sends a human readable
# uptime string 1h 41m 32s instead of 6092 seconds
- platform: uptime
name: $friendly_name Uptime
id: uptime_sensor
update_interval: 60s
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
# Custom C++ code to generate the result
state: !lambda |-
int seconds = round(id(uptime_sensor).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
(days ? to_string(days) + "d " : "") +
(hours ? to_string(hours) + "h " : "") +
(minutes ? to_string(minutes) + "m " : "") +
(to_string(seconds) + "s")
).c_str();
########################################################
# START THE FAN CONTROLLER SETUP
- platform: template
name: $friendly_name p term
id: p_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name i term
id: i_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name d term
id: d_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name output value
unit_of_measurement: "%"
id: o_term
accuracy_decimals: 2
- platform: template
name: $friendly_name error value
id: e_term
accuracy_decimals: 2
- platform: template
name: $friendly_name is in deadband
id: in_deadband_term
accuracy_decimals: 0
# GET TEMP NTC
- platform: ntc
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 100kOhm
name: "Temperature"
id: console_fan_temperature
accuracy_decimals: 1
filters:
- sliding_window_moving_average:
window_size: 10
send_every: 10
- offset: 0
# Example source sensors:
- platform: resistance
id: resistance_sensor
sensor: source_sensor
configuration: UPSTREAM
resistor: 10kOhm
name: Resistance Sensor
- platform: adc
id: source_sensor
pin: A0
update_interval: 1s
# Take the "COOL" value of the pid and send
# it to the frontend to graph the output voltage
- platform: pid
name: "Fan Speed (PWM Voltage)"
climate_id: console_thermostat
type: COOL
output:
- platform: esp8266_pwm
id: console_fan_speed
pin:
number: 2
min_power: 0.05 #Slowest Speed for Noctua Fans is 5% - Set to 0 for 'Other' Fans
frequency: 22.5kHz #Pulse the fan fast to prevent noise
- platform: gpio
pin: 0
id: fan_mosfet
fan:
- platform: speed
output: console_fan_speed
name: "Fan mosfet"
on_turn_on:
- output.turn_on: fan_mosfet
- output.turn_on: console_fan_speed
on_turn_off:
- output.turn_off: fan_mosfet
- output.turn_off: console_fan_speed
climate:
- platform: pid
name: "Console Fan Thermostat"
id: console_thermostat
sensor: console_fan_temperature
# It is summer right now, so 30c is a decent target.
default_target_temperature: 30°C
cool_output: console_fan_speed
# ON state change, publish the values to the x_term numbers defined
# above, so that they can be viewed in HA
on_state:
- sensor.template.publish:
id: p_term
state: !lambda 'return -id(console_thermostat).get_proportional_term() * 100.0;'
- sensor.template.publish:
id: i_term
state: !lambda 'return -id(console_thermostat).get_integral_term()* 100.0;'
- sensor.template.publish:
id: d_term
state: !lambda 'return -id(console_thermostat).get_derivative_term()* 100.0;'
- sensor.template.publish:
id: o_term
state: !lambda 'return -id(console_thermostat).get_output_value()* 100.0;'
- sensor.template.publish:
id: in_deadband_term
state: !lambda 'return id(console_thermostat).in_deadband();'
- sensor.template.publish:
id: e_term
state: !lambda 'return -id(console_thermostat).get_error_value();'
# The extents of the HA Thermostat
visual:
min_temperature: 15 °C
max_temperature: 60 °C
# See the README for setting up these parameters.
# These are over ridden by the number templates above.
control_parameters:
kp: 0.3
ki: 0.0015
kd: 0
max_integral: 0.0
output_averaging_samples: 1
derivative_averaging_samples: 5
# How to behave when close to the target temperature?
deadband_parameters:
threshold_high: 0.4°C
threshold_low: -1.0°C
kp_multiplier: 0.0
ki_multiplier: 0.04
kd_multiplier: 0.0
deadband_output_averaging_samples: 15
switch:
# Expose an ESP8266 restart button to HA
- platform: restart
name: ${friendly_name} ESP8266 Restart
id: console_fan_restart
# Restart every day at 12:30am.
# I've had some memory issues lockup
# the device after a couple weeks
time:
- platform: homeassistant
on_time:
# Every morning at 05:30am
- seconds: 0
minutes: 30
hours: 05
then:
- switch.turn_on: console_fan_restart
# I was able to find good KP,KI,KD values manually, per the instructions,
# but you can try pressing the autotune button from home assistant and copying the
# values it produces.
# See more at: https://esphome.io/components/climate/pid.html#climate-pid-autotune-action
button:
- platform: template
name: "PID Climate Autotune"
on_press:
- climate.pid.autotune: console_thermostat
It is hard to parse your comment this way, can you put your yaml in a code block? Just surround it with ``` before and after the code.
I changed my code a lot in the mean time and right now I have a much simpler version, where the fans are always on if my receiver is on in the TV cabinet that I'm cooling. Since I'm using two 140mm fans I literally don't hear them anyway on the lowest speed.
It simply imports a binary sensor from home assistant to check if the receiver is on, and if it is, switches the climate to COOL and turns on the relay and PWM. I also added a few simple buttons to be able to do it by hand (but I never have to use them anymore). My code now looks as follows:
substitutions:
friendly_name: Receiver Fan
esphome:
name: tv-meubel-fan-links
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "redacted"
ota:
password: "redacted"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: none
fast_connect: true
dallas:
- pin: 26
update_interval: 10s
binary_sensor:
- platform: homeassistant
id: receiver_power
entity_id: binary_sensor.receiver_power
on_state:
then:
- script.execute: toggle_climate
script:
- id: toggle_climate
mode: restart
then:
if:
condition:
binary_sensor.is_on: receiver_power
then:
- climate.control:
id: receiver_thermostat
mode: "COOL"
else:
- delay: 5 min
- climate.control:
id: receiver_thermostat
mode: "OFF"
sensor:
# ########################################################
# # START THE FAN CONTROLLER SETUP
- platform: template
name: $friendly_name p term
id: p_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name i term
id: i_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name d term
id: d_term
unit_of_measurement: "%"
accuracy_decimals: 2
- platform: template
name: $friendly_name output value
unit_of_measurement: "%"
id: o_term
accuracy_decimals: 2
- platform: template
name: $friendly_name error value
id: e_term
accuracy_decimals: 2
- platform: dallas
address: 0x940000000ca14e28
name: "Receiver Temperature"
id: receiver_temperature
accuracy_decimals: 1
filters:
- filter_out: 85.0
- throttle: 30s
# Take the "COOL" value of the pid and send
# it to the frontend to graph the output voltage
- platform: pid
name: "Fan Speed (PWM Voltage)"
climate_id: receiver_thermostat
type: COOL
output:
- platform: ledc
id: fan_speed
pin: GPIO19
frequency: "25000 Hz"
switch:
- platform: gpio
name: PWM gpio
pin:
number: GPIO18
inverted: true
id: pwm_on
- platform: gpio
name: Fan Power
pin:
number: GPIO03
id: fan_supply
climate:
- platform: pid
name: "Receiver Fan Thermostat"
id: receiver_thermostat
sensor: receiver_temperature
default_target_temperature: 33°C
cool_output: fan_speed
deadband_parameters:
threshold_high: 0.4°C
threshold_low: -1.0°C
kp_multiplier: 0.0 # proportional gain turned off inside deadband
ki_multiplier: 0.2 # integral accumulates at only 20% of normal ki
kd_multiplier: 0.0 # derviative is turned off inside deadband
deadband_output_averaging_samples: 10 # average the output over 10 samples within the deadband
on_state:
- sensor.template.publish:
id: p_term
state: !lambda 'return -id(receiver_thermostat).get_proportional_term() * 100.0;'
- sensor.template.publish:
id: i_term
state: !lambda 'return -id(receiver_thermostat).get_integral_term()* 100.0;'
- sensor.template.publish:
id: d_term
state: !lambda 'return -id(receiver_thermostat).get_derivative_term()* 100.0;'
- sensor.template.publish:
id: o_term
state: !lambda 'return -id(receiver_thermostat).get_output_value()* 100.0;'
- sensor.template.publish:
id: e_term
state: !lambda 'return -id(receiver_thermostat).get_error_value();'
- if:
condition:
and:
- lambda: 'return id(receiver_thermostat).mode == esphome::climate::ClimateMode::CLIMATE_MODE_OFF;'
- switch.is_on: fan_supply
- switch.is_on: pwm_on
then:
- switch.turn_off: fan_supply
- switch.turn_off: pwm_on
- logger.log: "Fan switched off"
- if:
condition:
and:
- lambda: 'return id(receiver_thermostat).mode != esphome::climate::ClimateMode::CLIMATE_MODE_OFF;'
- switch.is_off: fan_supply
- switch.is_off: pwm_on
then:
- switch.turn_on: fan_supply
- switch.turn_on: pwm_on
- logger.log: "Fan switched on"
# The extents of the HA Thermostat
visual:
min_temperature: 20 °C
max_temperature: 50 °C
temperature_step: 1 °C
# See the README for setting up these parameters.
# These are over ridden by the number templates above.
control_parameters:
kp: 0.05
ki: 0.0002
kd: 0
max_integral: 0.0
output_averaging_samples: 4
i set the fan at 0% and 50% but still it wont stop running totally, do you know what i can do