substitutions: deviceName: "Bathroom Fan" deviceLowerCaseName: "bathroom-fan" deviceComment: "ElectroDragon Extractor Fan" # Onboard status LED pinStatusLED: "10" # The pins controlling the RGBW terminals pinWhite: "04" pinBlue: "05" pinGreen: "06" pinRed: "07" # One pin can be switched to 5v out signalling, which we use for the Fan PWM signalling pinWS28xx: "09" # We need pins for: IR sensor, Fan RPM sensor, and i2c (SDA+SCL) pinPIR: "01" pinRPM: "03" pinSDA: "02" pinSCL: "08" ######################################################## ## General setup of device, network etc ## ######################################################## esphome: name: "${deviceLowerCaseName}" friendly_name: "${deviceName}" comment: "${deviceComment}" esp32: board: esp32-c3-devkitm-1 framework: type: arduino # Enable logging logger: # Enable Home Assistant API api: encryption: key: !secret api_enckey ota: password: !secret ota_password platform: esphome wifi: ssid: !secret wifi_ssid # Set your SSID in ESPHome's Secret file password: !secret wifi_password # Set your WiFi password in ESPHome's Secret file # Enable fallback hotspot (captive portal) in case wifi connection fails # Note: ESP32-C3s can get stuck in boot-loop if this or captive_portal is removed (known issue) ap: ssid: "AP-${deviceName}" password: "ESPHOME" # Consider changing this captive_portal: ##################################################### ## Setup of Status Light ## ## Off when running, blinks in case or error ## ##################################################### light: - platform: status_led # Oboard status_led indicates errors/warnings during boot + operation id: statusled name: "Status LED" pin: ${pinStatusLED} disabled_by_default: True # No need to reflect in Home Assistant ##################################################### ## Setup of Fan ## ## ## ##################################################### power_supply: # Optional control of fan to switch off power completely - id: fanPower pin: ${pinBlue} output: # PMW control of fan using the LEDC platform - platform: ledc pin: ${pinWS28xx} id: fanPin power_supply: fanPower # Which pin to use to turn off Fan completely frequency: 19531Hz # Higher frequency, but only 12-bit resolution (4096 gradiant steps) fan: # Very basic fan with no oscilation etc control - platform: speed output: fanPin #oscillation: #direction_output: speed_count: 100 name: "Extractor Fan" id: Extractor restore_mode: ALWAYS_ON # Default to turning on, to help with installation icon: mdi:fan ##################################################### ## Setup of Sensors: ## ## Motion (IR), Humidity, Temperatur ## ##################################################### # Need i2c bus to control the humidity+temperature sensor i2c: sda: ${pinSDA} scl: ${pinSCL} scan: true id: bus_a ## PIR Sensor AM312 binary_sensor: - platform: gpio name: "Motion" # IR Presense detection, halves fan speed id: pirSensor # ToDo: Call script to trigger immediately pin: number: ${pinPIR} mode: input: True pulldown: True device_class: motion filters: - delayed_off: 180s sensor: - platform: pulse_meter # Warning: Not been tested, TACHO impulses fried ESP32 somehow name: "RPM" id: rpmSensor unit_of_measurement: 'RPM' state_class: measurement accuracy_decimals: 0 pin: number: ${pinRPM} inverted: true mode: input: true pullup: true filters: - multiply: 0.5 # 2 impulses per rotation, /2 to get RPM - throttle_average: 10s # Only update every 10 seconds - filter_out: nan - delta: 10% # And further reduce updates if change is small - platform: sht3xd # Temp + Humidity sensor address: 0x44 update_interval: 60s # Faster interval gives smoother fan speed changes, but also spams logs temperature: name: "Temperature" # We only use Temp for information. SHT3x uses it for Relative Humidity id: temp humidity: name: "Humidity" id: humid filters: - clamp: # Clamp to get rid of bad readings min_value: 0.1 max_value: 99.9 ignore_out_of_range: true - delta: 2.0 # Don't react to every small change on_value: then: if: condition: sensor.in_range: # We're always in range due to the Clamp above id: humid above: 0 below: 100 then: - lambda: |- # ToDo: Convert to script and call it float cutoff = id(lowHumCutoff).state; // Doing linear transform here because we need the id(lowHumCutoff) variable // Max is 100 at 80% // Min is 25 at cutoff% // linear equation y = mx + c // = ((100-25) / (80 - $C$5)) * B8 + (100 - (((100-25) / (80 - $C$5))*80)) float speed = (75/(80-cutoff)) * x + (100-((75/ (80-cutoff))*80)); // Clamp between 25 and 100 if( x <= cutoff ) speed = 25; if( x >= 80) speed = 100; // Test if we need to go slow if( id(quietModeSwitch).state || id(pirSensor).state ) speed = speed / 2; // Turn the fan on and set the speed, or turn off if( x >= cutoff ) { auto call = id(Extractor).turn_on(); call.set_speed(speed); call.perform(); } else { auto call = id(Extractor).turn_off(); call.perform(); } ##################################################### ## Setup of Home Assistant controls ## ## "Quiet Mode", "Low Humidity Cutoff" ## ##################################################### switch: - platform: template name: "Quiet Mode" # Quiet Mode halves the fan-speed, similar to Presence Detection id: quietModeSwitch optimistic: True # turn_on_action: # ToDo: Allow switch to control fan speed immediately via script # - switch.turn_on: switch2 # turn_off_action: # - switch.turn_on: switch1 number: - platform: template # Control in Home Assistant to set point where fan should turn off id: lowHumCutoff name: "Low Humidity Cutoff" icon: mdi:waterpercent disabled_by_default: True # User has to activate the control in the HASS UI entity_category: "" optimistic: True min_value: 1 max_value: 100 step: 1 initial_value: 35 # 35% rel humidity is slightly high as low cutoff restore_value: True