I’m trying to use ESPHome for the automation of a fan. At the moment I’m using a custom made program on a ESP8266 to do this, but I want to replace this program with ESPHome.
The problem is that I don’t know how to do this using ESPHome so any help would be appreciated.
I control the fan using Home Assistant. In Home Assistant I have an input_select (low/medium/high) with an automation that sends MQTT messages to a specific topic. The ESP module subscribes to the topic and sets some GPIO pins.
The problem is that I have to update multiple GPIO pins (multiple relays):
GPIO4 Low, GPIO5 Low -> Fan at low speed
GPIO4 High, GPIO5 Low -> Fan at medium speed
GPIO4 Low, GPIO5 High -> Fan at high speed
The fan cannot be turned off (default is low speed). I want to replace the MQTT part by the HA <-> EPSHome API.
I’m not sure how to do this in an ESPHome configuration. I know that I can define two switches in ESPHome and control them using HA but it would be great to have one single HA entity connected to EPSHome.
The reason for this is that the GPIOs may not be HIGH at the same time! So I would like to restrict this inside the ESPHome program.
Can anybody give me an ESPHome config example of how to connect my HA input_select to the ESPHome module?
glmnet
(Guillermo Ruffino)
September 14, 2019, 6:57pm
2
You can’t do it.
Ideally you’ll use the fan integration. However it only supports two types of fan, binary and speed fan. The problem is speed fan has an analog output and you need three discrete outputs.
This could be tackled by a template fan however that does not exist yet.
Curiously a few hours ago somebody filled a feature request for that
In any case you can take a solution with no fan integration. You can use the interlocking option of output to prevent more than one output on at a time.
1 Like
WWolkers
(Wouter Wolkers)
September 14, 2019, 7:17pm
3
The onyl way I see is to make a custom component…
here’s an example, this is what I use for my fan:
#include "esphome.h"
using namespace esphome;
#define PIN_1 18
#define PIN_2 19
#define PIN_3 21
class MyCustomFanoutput : public Component, public FloatOutput {
public:
void setup() override {
// This will be called by App.setup()
pinMode(PIN_1, OUTPUT);
pinMode(PIN_2, OUTPUT);
pinMode(PIN_3, OUTPUT);
}
void write_state(float state) override {
if (state == 0.33) {
digitalWrite(PIN_1, HIGH);
delay(25);
digitalWrite(PIN_1, LOW);
}
else if (state == 0.66) {
digitalWrite(PIN_2, HIGH);
delay(25);
digitalWrite(PIN_2, LOW);
}
else if (state == 1) {
digitalWrite(PIN_3, HIGH);
delay(25);
digitalWrite(PIN_3, LOW);
}
}
};
2 Likes
Thanks for the code example. I’ve created my own custom component and connected it to HA. Seems to work fine now!
WWolkers
(Wouter Wolkers)
September 15, 2019, 12:17pm
5
Happy to help.
I should post that example on the esphome website probably
2 Likes
This looks really interesting! Could you please also post the yaml part that refers to your ‘MyCustomFanoutput’? Thanks!
WWolkers
(Wouter Wolkers)
October 24, 2019, 7:20am
7
sure:
esphome:
name: mechanische_ventilatie
platform: ESP32
board: esp-wrover-kit
includes:
- custom_fan.h
wifi:
ssid: "SSID"
password: "password"
# Enable logging
logger:
web_server:
# Enable Home Assistant API
api:
password: "password"
ota:
password: "password"
mqtt:
broker: mqttip
username: user
password: password
output:
- platform: custom
type: float
lambda: |-
auto my_custom_fan_output = new MyCustomFanoutput();
App.register_component(my_custom_fan_output);
return {my_custom_fan_output};
outputs:
id: my_custom_fan
fan:
- platform: speed
output: my_custom_fan
name: "Mechanische Ventilatie"
command_topic: "esphome/mechanische_ventilatie/commands"
# speed_command_topic: "esp/mv"
# speed_state_topic: 'mechanische_ventilatie/on/state'
state_topic: 'mechanische_ventilatie/on/state'
# payload_on: '{"mac": "000D6F00002369B9", "cmd": "switch", "val": "on"}'
# payload_off: '{"mac": "000D6F00002369B9", "cmd": "switch", "val": "off"}'
1 Like
I have made a version that is just using a 4-way relay board with these to control the light and the fan.
It has been very painful but works perfectly (stand alone too!) with this code.
esphome:
name: newer_fan_test
platform: ESP8266
board: d1_mini
includes:
- ifan02.h
wifi:
ssid: "*********"
password: "********"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Newer Fan Test Fallback Hotspot"
password: "**********"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
binary_sensor:
- platform: template
id: led_low
lambda: |-
if (id(test_fan).speed == 0){
if(id(test_fan).state){
return true;
} else {
return false;
}
} else {
return false;
}
on_press:
then:
- light.turn_on:
id: switch_led
brightness: 30%
- switch.turn_on:
id: dim_led
- platform: template
id: led_mid
lambda: |-
if (id(test_fan).speed == 1){
if(id(test_fan).state){
return true;
} else {
return false;
}
} else {
return false;
}
on_press:
then:
- light.turn_on:
id: switch_led
brightness: 60%
- switch.turn_on:
id: dim_led
- platform: template
id: led_high
lambda: |-
if (id(test_fan).speed == 2){
if(id(test_fan).state){
return true;
} else {
return false;
}
} else {
return false;
}
on_press:
then:
- light.turn_on:
id: switch_led
brightness: 100%
- switch.turn_on:
id: dim_led
- platform: template
id: led_off
lambda: |-
if (id(test_fan).state){
return false;
} else {
return true;
}
on_press:
then:
- light.turn_off:
id: switch_led
- switch.turn_off:
id: dim_led
##---light switch button--------------------------
- platform: gpio
pin: GPIO3
id: light_button
on_release:
then:
- switch.toggle: mancave_light
##---right rotation on the two-way switch---------
- platform: gpio
pin: D8
id: up
on_press:
then:
- lambda: |-
if (id(test_fan).state) {
if (id(test_fan).speed == 0) {
id(fan_med).turn_on();
ESP_LOGD("main", "Fan set to Medium");
} else {
if (id(test_fan).speed == 1){
id(fan_high).turn_on();
ESP_LOGD("main", "Fan set to High");
} else {
id(fan_off).turn_on();
ESP_LOGD("main", "Fan set to Off");
}
}
} else {
id(fan_low).turn_on();
ESP_LOGD("main", "Fan set to Low");
}
- platform: gpio
pin: D7
id: down
on_press:
then:
- lambda: |-
if (id(test_fan).state) {
if (id(test_fan).speed == 0) {
id(fan_off).turn_on();
ESP_LOGD("main", "Fan set to Off");
} else {
if (id(test_fan).speed == 1){
id(fan_low).turn_on();
ESP_LOGD("main", "Fan set to Low");
} else {
id(fan_med).turn_on();
ESP_LOGD("main", "Fan set to Medium");
}
}
} else {
id(fan_high).turn_on();
ESP_LOGD("main", "Fan set to High");
}
fan:
- platform: speed
output: fanoutput
id: test_fan
name: "Fan"
output:
- platform: custom
type: float
outputs:
id: fanoutput
lambda: |-
auto test_fan = new FanOutput();
App.register_component(test_fan);
return {test_fan};
##-----ring light on two-way switch------
- platform: esp8266_pwm
id: switch_light
pin: D5
##-----ring light for light button-------
- platform: esp8266_pwm
id: button_light
pin: D6
switch:
- platform: gpio
pin: D4
id: relay1
inverted: yes
- platform: gpio
pin: D3
id: relay2
inverted: yes
- platform: gpio
pin: D2
id: relay3
inverted: yes
- platform: gpio
pin: D1
id: mancave_light
name: "light"
inverted: yes
- platform: template
id: fan_off
lambda: |-
if (id(test_fan).state){
return false;
} else {
return true;
}
turn_on_action:
- fan.turn_off:
id: test_fan
- platform: template
id: fan_low
turn_on_action:
- fan.turn_on:
id: test_fan
speed: LOW
- platform: template
id: fan_med
turn_on_action:
- fan.turn_on:
id: test_fan
speed: MEDIUM
- platform: template
id: fan_high
turn_on_action:
- fan.turn_on:
id: test_fan
speed: HIGH
- platform: template
id: dim_led
turn_on_action:
- delay: 5s
- if:
condition:
- switch.is_on: fan_off
then:
- light.turn_off:
id: switch_led
else:
- light.turn_on:
id: switch_led
brightness: 10%
light:
- platform: monochromatic
name: "fan switch led"
id: switch_led
output: switch_light
default_transition_length: 0.5s
- platform: monochromatic
name: "light switch led"
id: button_led
output: button_light
default_transition_length: 0.5s
A bit of an explanation of whats going on…
The - button (or left toggle) on the “rocker” steps the fan speeds down to off and then back to high and so on, and also updates it in home assistant. The +button (or right toggle) steps the fan speeds up in the same manner.
The led ring on the fan controller is displayed at 100% on high, 60% on medium, on 30% on low and off when off. This is all well and good until you want the fan on at night but not a bright light in ya face so I have also made it dim after 5 seconds to 10% on any speed setting when it is on and again off when off.
3 Likes
bkt92
(Bùi Khắc Tú)
June 16, 2020, 11:15am
10
Hey, can you tell me what is your modification of ifan02.h? I also use 4 relay board to control my fan.
AaronCake
(Aaron Cake)
June 16, 2020, 3:00pm
11
Where did you get the button on the right?
I am trying to get the same result with a Shelly 2.5, I want to control the following fan:
GPIO4 Low, GPIO15 Low -> Fan at low speed
GPIO4 High, GPIO15 Low -> Fan at medium speed
GPIO4 High, GPIO15 High -> Fan at high speed
I tried the example from @WWolkers , but I cannot get it working. When turning on the fan, the ouput both go high. But I cannot get one of them to go low again.
I have the following custom component:
#include "esphome.h"
using namespace esphome;
#define PIN_1 4
#define PIN_2 15
class MyCustomFanoutput : public Component, public FloatOutput {
public:
void setup() override {
// This will be called by App.setup()
pinMode(PIN_1, OUTPUT);
pinMode(PIN_2, OUTPUT);
}
void write_state(float state) override {
if (state == 0.33) {
digitalWrite(PIN_1, LOW);
digitalWrite(PIN_2, LOW);
}
else if (state == 0.66) {
digitalWrite(PIN_1, HIGH);
digitalWrite(PIN_2, LOW);
}
else if (state == 1) {
digitalWrite(PIN_1, HIGH);
digitalWrite(PIN_2, HIGH);
}
}
};
And this is my YAML:
esphome:
name: ventilatie
platform: ESP8266
board: esp01_1m
includes:
- custom_fan.h
wifi:
ssid: !secret SSID
password: !secret wifi_pass
domain: !secret domain
manual_ip:
static_ip: 192.168.5.215
gateway: 192.168.5.254
subnet: 255.255.255.0
logger:
api:
ota:
password: !secret OTA_pass
output:
- platform: custom
type: float
lambda: |-
auto my_custom_fan_output = new MyCustomFanoutput();
App.register_component(my_custom_fan_output);
return {my_custom_fan_output};
outputs:
id: my_custom_fan
fan:
- platform: speed
output: my_custom_fan
name: "Ventilatie"
Can you help me with this?
I managed to create a working version without the custom component as the expansion board I wanted to use wouldn’t allow the custom component and it works perfectly!!
esphome:
name: sx1509_newer_fan_test
platform: ESP8266
board: d1_mini
wifi:
ssid: "wifi"
password: "password"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Sx1509 Newer Fan Test"
password: "***************"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
i2c:
sda: D2
scl: D1
scan: True
id: bus_a
sx1509:
- id: sx1509_hub1
address: 0x3E
fan:
- platform: speed
id: living_fan
output: my_output_1
name: "Living Room Fan"
output:
- platform: sx1509
sx1509_id: sx1509_hub1
id: 'button2_led_output'
pin: 4
inverted: true
- platform: sx1509
sx1509_id: sx1509_hub1
id: 'button1_led_output'
pin: 2
inverted: true
- platform: sx1509
sx1509_id: sx1509_hub1
id: 'fan_led_output'
pin: 7
inverted: true
- platform: template
id: my_output_1
type: float
write_action:
- if:
condition:
lambda: return ((state == 0));
then:
- switch.turn_off: relay2
- switch.turn_off: relay3
- switch.turn_off: relay1
- light.turn_off: switch_led
- if:
condition:
lambda: return ((state > 0) && (state < .34));
then:
- switch.turn_off: relay2
- switch.turn_off: relay3
- switch.turn_on: relay1
- light.turn_on:
id: switch_led
brightness: 30%
- switch.turn_on: dim_led
- if:
condition:
lambda: return ((state > .34) && (state < .7));
then:
- switch.turn_off: relay1
- switch.turn_off: relay3
- switch.turn_on: relay2
- light.turn_on:
id: switch_led
brightness: 60%
- switch.turn_on: dim_led
- if:
condition:
lambda: return ((state == 1));
then:
- switch.turn_off: relay1
- switch.turn_off: relay2
- switch.turn_on: relay3
- light.turn_on:
id: switch_led
brightness: 100%
- switch.turn_on: dim_led
binary_sensor:
- platform: gpio
name: "SX1509 Pin #0"
pin:
sx1509: sx1509_hub1
number: 3
mode: INPUT_PULLUP
inverted: True
on_press:
then:
- light.toggle: button2_led
- platform: gpio
name: "SX1509 Pin #2"
pin:
sx1509: sx1509_hub1
number: 0
mode: INPUT_PULLUP
inverted: True
on_press:
then:
if:
condition:
switch.is_on: relay4
then:
- switch.turn_off: relay4
else:
- switch.turn_on: relay4
- light.turn_off: button1_led
- platform: gpio
id: "fan_up"
pin:
sx1509: sx1509_hub1
number: 6
mode: INPUT_PULLUP
inverted: True
on_press:
then:
- lambda: |-
if (id(living_fan).state) {
if (id(living_fan).speed == 0) {
id(fan_off).turn_on();
ESP_LOGD("main", "Fan set to Off");
} else {
if (id(living_fan).speed == 1){
id(fan_low).turn_on();
ESP_LOGD("main", "Fan set to Low");
} else {
id(fan_med).turn_on();
ESP_LOGD("main", "Fan set to Medium");
}
}
} else {
id(fan_high).turn_on();
ESP_LOGD("main", "Fan set to High");
}
- platform: gpio
id: "fan_down"
pin:
sx1509: sx1509_hub1
number: 5
mode: INPUT_PULLUP
inverted: True
on_press:
then:
- lambda: |-
if (id(living_fan).state) {
if (id(living_fan).speed == 0) {
id(fan_med).turn_on();
ESP_LOGD("main", "Fan set to Medium");
} else {
if (id(living_fan).speed == 1){
id(fan_high).turn_on();
ESP_LOGD("main", "Fan set to High");
} else {
id(fan_off).turn_on();
ESP_LOGD("main", "Fan set to Off");
}
}
} else {
id(fan_low).turn_on();
ESP_LOGD("main", "Fan set to Low");
}
###motion sensor
- platform: gpio
name: "Living Motion"
pin:
sx1509: sx1509_hub1
number: 1
mode: INPUT
inverted: false
on_press:
then:
- if:
condition:
switch.is_off: relay4
then:
- light.turn_on: button1_led
- delay: 5s
- light.turn_off: button1_led
switch:
- platform: gpio
name: "sx1509_ relay1"
id: relay1
pin:
sx1509: sx1509_hub1
number: 8
mode: OUTPUT
inverted: True
- platform: gpio
name: "sx1509_ relay2"
id: relay2
pin:
sx1509: sx1509_hub1
number: 9
mode: OUTPUT
inverted: True
- platform: gpio
name: "sx1509_ relay3"
id: relay3
pin:
sx1509: sx1509_hub1
number: 10
mode: OUTPUT
inverted: True
- platform: gpio
name: "Living Room Light"
id: relay4
pin:
sx1509: sx1509_hub1
number: 11
mode: OUTPUT
inverted: True
- platform: template
id: fan_off
lambda: |-
if (id(living_fan).state){
return false;
} else {
return true;
}
turn_on_action:
- fan.turn_off:
id: living_fan
- platform: template
id: fan_low
turn_on_action:
- fan.turn_on:
id: living_fan
speed: LOW
- platform: template
id: fan_med
turn_on_action:
- fan.turn_on:
id: living_fan
speed: MEDIUM
- platform: template
id: fan_high
turn_on_action:
- fan.turn_on:
id: living_fan
speed: HIGH
- platform: template
id: dim_led
turn_on_action:
- delay: 5s
- if:
condition:
- switch.is_on: fan_off
then:
- light.turn_off:
id: switch_led
else:
- light.turn_on:
id: switch_led
brightness: 15%
light:
- platform: monochromatic
id: button1_led
name: "Living Room Button1 Led"
output: button1_led_output
default_transition_length: 0.5s
- platform: monochromatic
id: button2_led
name: "Living Room Button2 Led"
output: button2_led_output
default_transition_length: 0.5s
- platform: monochromatic
id: switch_led
name: "Living Room Switch Led"
output: fan_led_output
default_transition_length: 0.5s
I might create a basic straight forward example of this and upload it to the creation page as there is next to no instructions on how to create a float output for the fan.
1 Like
Hi Erwin
Try this out and let me know how you go, I’m not sure how you plan to turn the fan off but according to your plan this code might work for you…
esphome:
name: ventilatie
platform: ESP8266
board: esp01_1m
wifi:
ssid: !secret SSID
password: !secret wifi_pass
domain: !secret domain
manual_ip:
static_ip: 192.168.5.215
gateway: 192.168.5.254
subnet: 255.255.255.0
logger:
api:
ota:
password: !secret OTA_pass
output:
- platform: template
id: custom_fan
type: float
write_action:
- if:
condition:
lambda: return ((state == 0));
then:
# action for off
- switch.turn_off: relay1
- switch.turn_off: relay2
- if:
condition:
lambda: return ((state > 0) && (state < .34));
then:
# action for low
- switch.turn_off: relay1
- switch.turn_off: relay2
- if:
condition:
lambda: return ((state > .34) && (state < .7));
then:
# action for medium
- switch.turn_on: relay1
- switch.turn_off: relay2
- if:
condition:
lambda: return ((state == 1));
then:
# action for high
- switch.turn_on: relay1
- switch.turn_on: relay2
fan:
- platform: speed
id: ventilatie
output: custom_fan
name: "Ventilatie"
switch:
- platform: gpio
name: "relay 1"
id: relay1
pin: GPIO4
- platform: gpio
name: "relay 2"
id: relay2
pin: GPIO15
4 Likes
ptv
(Dmitry)
May 21, 2021, 4:45am
16
Hi. I use self programmed recuperator a lot of time. Both motors are controlled by dimmers with zero cross sensor. Best library for linear motor manipulation i found there .
Now I try to use HomeAssistant and ESPHome for better communication between them, but ESPHome have not linearized dimmer output (i try this ). Slow speeds do not move motors at all, motor starts at about 40% and no significant motor speed change between 40-100%
Is it possible and how to use Arduino library to manipulate dimmer? Are any recommendations how to manipulate motor (fan) via dimmer with zero cross detection?