Skip to content

Instantly share code, notes, and snippets.

@ndbroadbent
Created September 6, 2022 23:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndbroadbent/63aa5f105e21631bee4ff9a62c9b1608 to your computer and use it in GitHub Desktop.
Save ndbroadbent/63aa5f105e21631bee4ff9a62c9b1608 to your computer and use it in GitHub Desktop.
Rangehood ESP32 Controller - ESPHome Configuration
esphome:
name: rangehood
includes:
- rangehood_button_leds.h
esp32:
board: nodemcu-32s
framework:
type: arduino
# Had to write a custom C++ component to flip the same pins between input/output
# to read the buttons and also light up the LEDs on the button panel.
custom_component:
- lambda: |-
auto button_leds = new RangehoodButtonLedsComponent();
return {button_leds};
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "..."
ota:
password: "..."
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: none
output_power: 20
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Rangehood Fallback Hotspot"
password: "..."
captive_portal:
light:
- platform: binary
id: rangehood_light
name: "Rangehood Light"
output: rangehood_light_output
fan:
- platform: speed
id: rangehood_fan
name: "Rangehood Fan"
speed_count: 3
output: rangehood_fan_output
globals:
- id: rangehood_fan_speed
type: float
restore_value: no
initial_value: '0'
- id: rangehood_light_state
type: boolean
restore_value: no
initial_value: 'false'
output:
- platform: template
id: rangehood_light_output
type: binary
write_action:
- lambda: |-
if (
(state && !id(rangehood_light_state)) ||
(!state && id(rangehood_light_state))
) {
id(rangehood_light_trigger).turn_on();
id(rangehood_light_state) = state;
}
- platform: template
id: rangehood_fan_output
type: float
write_action:
- lambda: |-
if (state == 0) {
if (id(rangehood_fan_speed) > 0) {
// Turn off the fan by pressing the current speed button
if (id(rangehood_fan_speed) < 0.34) {
id(rangehood_fan_1_trigger).turn_on();
} else if (id(rangehood_fan_speed) < 0.67) {
id(rangehood_fan_2_trigger).turn_on();
} else { // 1.0
id(rangehood_fan_3_trigger).turn_on();
}
}
} else if (state < 0.34) {
// Make sure it's not already set to speed 1
if (id(rangehood_fan_speed) < 0.32 || id(rangehood_fan_speed) > 0.34) {
id(rangehood_fan_1_trigger).turn_on();
}
} else if (state < 0.67) {
if (id(rangehood_fan_speed) < 0.65 || id(rangehood_fan_speed) > 0.67) {
id(rangehood_fan_2_trigger).turn_on();
}
} else { // 1
if (id(rangehood_fan_speed) != 1.0) {
id(rangehood_fan_3_trigger).turn_on();
}
}
// Update global variable to new state
id(rangehood_fan_speed) = state;
switch:
- platform: gpio
internal: true
restore_mode: ALWAYS_OFF
pin: 26
id: rangehood_light_trigger
interlock: &trigger_interlock_group [rangehood_light_trigger, rangehood_fan_1_trigger, rangehood_fan_2_trigger, rangehood_fan_3_trigger]
on_turn_on:
- delay: 100ms
- switch.turn_off: rangehood_light_trigger
- platform: gpio
internal: true
restore_mode: ALWAYS_OFF
pin: 25
id: rangehood_fan_1_trigger
interlock: *trigger_interlock_group
on_turn_on:
- delay: 100ms
- switch.turn_off: rangehood_fan_1_trigger
- platform: gpio
internal: true
restore_mode: ALWAYS_OFF
pin: 23
id: rangehood_fan_2_trigger
interlock: *trigger_interlock_group
on_turn_on:
- delay: 100ms
- switch.turn_off: rangehood_fan_2_trigger
- platform: gpio
internal: true
restore_mode: ALWAYS_OFF
pin: 22
id: rangehood_fan_3_trigger
interlock: *trigger_interlock_group
on_turn_on:
- delay: 100ms
- switch.turn_off: rangehood_fan_3_trigger
#include "esphome.h"
#define LIGHT_PIN 17
#define FAN_3_PIN 16
#define OUTPUT_TOGGLE_PIN 18
#define FAN_2_PIN 19
#define FAN_1_PIN 21
class RangehoodButtonLedsComponent : public Component {
public:
unsigned long lastChangedTime;
unsigned long currentTime;
int btnLight = 0;
int btnFan3 = 0;
int btnFan2 = 0;
int btnFan1 = 0;
int btnLightPrev = 0;
int btnFan3Prev = 0;
int btnFan2Prev = 0;
int btnFan1Prev = 0;
int loopCounter = 0;
void setup() override {
pinMode(OUTPUT_TOGGLE_PIN, OUTPUT);
lastChangedTime = millis();
}
void loop() override {
currentTime = millis();
bool debouncing = currentTime - lastChangedTime < 50;
// Read buttons
pinMode(LIGHT_PIN, INPUT_PULLUP);
pinMode(FAN_3_PIN, INPUT_PULLUP);
pinMode(FAN_2_PIN, INPUT_PULLUP);
pinMode(FAN_1_PIN, INPUT_PULLUP);
digitalWrite(OUTPUT_TOGGLE_PIN, LOW);
delayMicroseconds(3);
btnLight = digitalRead(LIGHT_PIN);
btnFan3 = digitalRead(FAN_3_PIN);
btnFan2 = digitalRead(FAN_2_PIN);
btnFan1 = digitalRead(FAN_1_PIN);
//loopCounter++;
//if (loopCounter >= 180) {
// loopCounter = 0;
// ESP_LOGD("rangehood_button_leds", "btnLight: %d", btnLight);
// ESP_LOGD("rangehood_button_leds", "btnFan3: %d", btnFan3);
// ESP_LOGD("rangehood_button_leds", "btnFan2: %d", btnFan2);
// ESP_LOGD("rangehood_button_leds", "btnFan1: %d", btnFan1);
//}
bool lightIsOn = id(rangehood_light).current_values.is_on();
bool fanIsOn = id(rangehood_fan).state;
if (!debouncing) {
if (btnLight != btnLightPrev) {
if (btnLight == 0) { // initial press
// ESP_LOGD("rangehood_button_leds", "lightIsOn before: %d", lightIsOn);
if (lightIsOn) {
id(rangehood_light).turn_off().perform();
lightIsOn = false;
} else {
id(rangehood_light).turn_on().perform();
lightIsOn = true;
}
}
btnLightPrev = btnLight;
lastChangedTime = currentTime;
}
if (btnFan3 != btnFan3Prev) {
if (btnFan3 == 0) { // initial press
if (fanIsOn && id(rangehood_fan).speed == 3) {
auto call = id(rangehood_fan).turn_off();
call.perform();
fanIsOn = false;
} else {
auto call = id(rangehood_fan).turn_on();
call.set_speed(3);
call.perform();
fanIsOn = true;
}
}
btnFan3Prev = btnFan3;
lastChangedTime = currentTime;
}
if (btnFan2 != btnFan2Prev) {
if (btnFan2 == 0) { // initial press
if (fanIsOn && id(rangehood_fan).speed == 2) {
auto call = id(rangehood_fan).turn_off();
call.perform();
fanIsOn = false;
} else {
auto call = id(rangehood_fan).turn_on();
call.set_speed(2);
call.perform();
fanIsOn = true;
}
}
btnFan2Prev = btnFan2;
lastChangedTime = currentTime;
}
if (btnFan1 != btnFan1Prev) {
if (btnFan1 == 0) { // initial press
if (fanIsOn && id(rangehood_fan).speed == 1) {
auto call = id(rangehood_fan).turn_off();
call.perform();
fanIsOn = false;
} else {
auto call = id(rangehood_fan).turn_on();
call.set_speed(1);
call.perform();
fanIsOn = true;
}
}
btnFan1Prev = btnFan1;
lastChangedTime = currentTime;
}
}
// Set LEDs until the next loop (16ms)
pinMode(LIGHT_PIN, OUTPUT);
pinMode(FAN_3_PIN, OUTPUT);
pinMode(FAN_2_PIN, OUTPUT);
pinMode(FAN_1_PIN, OUTPUT);
digitalWrite(LIGHT_PIN, lightIsOn ? LOW : HIGH);
digitalWrite(FAN_3_PIN, fanIsOn && id(rangehood_fan).speed == 3 ? LOW : HIGH);
digitalWrite(FAN_2_PIN, fanIsOn && id(rangehood_fan).speed == 2 ? LOW : HIGH);
digitalWrite(FAN_1_PIN, fanIsOn && id(rangehood_fan).speed == 1 ? LOW : HIGH);
delayMicroseconds(3);
digitalWrite(OUTPUT_TOGGLE_PIN, HIGH);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment