Turning old roomfan into hass compatible, schedulable air circulator

Hello!

I have one of these old bad boy.
image

I hate running it all the time, hate getting up and turning it on and off all the time… I also like to run it at night just to get the air moving a bit. But keeping it on for all night is a waste and gets me sick.

So i made the only logical solution… i integrated it into HASS :stuck_out_tongue:
i hade a basic Sonoff device that i used to control the fan.
The fan has 4 button to adjust the speed, but i always run it in the slowest option.

Heres the finished control panel:

You can:

  • Manually turn the fan On or OFF from hass webUI or from a Telegram bot button.
  • Turn it ON and set an automatic and an adjustable turn off timer. Timer range is 0-24hours + 0-60mins with 15min incremental
  • Turn it On with adjustable automatic OFF, adjustable automatic ON and how long should it loop.
    Think about this option like: You want the fan to be on for 15minutes, then it should be off for 45mins before it turns on again. Do this cycle for 6 hours. :slight_smile:

You need to have a basic SONOFF device and working hass MQTT

So anyway, heres the yamls:

#                           #
#####                    ####
#     Configuration.yaml    #
#####                    ####
#                           #
switch:
 - platform: mqtt
   name: "Sonoff - Room Fan"
   command_topic: "cmnd/sonoff/power"
   state_topic: "stat/sonoff/POWER"
   payload_on: "ON"
   payload_off: "OFF"
   qos: 1
   retain: true
#
sensor:
  - platform: time_date
    display_options:
      - 'time'
      - 'date_time'
 
  - platform: template
    sensors:
      bedroom_fan_state_timer:
        value_template:  "{% if is_state('input_boolean.enable_timer', 'on') and is_state('switch.sonoff__room_fan', 'on')%}turning off in: {{ (((states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) - (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_timer.last_updated)))| timestamp_utc).split(' ')[1]}}{% endif %}{% if is_state('input_boolean.enable_timer', 'off') and is_state('input_boolean.enable_circulation', 'on') %} turning on in: {{(((states.input_number.bedroomfan_air_circulation_hours.state |int *3600)+(states.input_number.bedroomfan_air_circulation_minutes.state |int *60)-(as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_timer.last_updated)))| timestamp_utc).split(' ')[1]}}{% endif %}"
        friendly_name: Current program
#       
input_number:
  bedroomfan_timer_hours:
    name: Keep on - Hours
    icon: mdi:timer
    initial: 0
    min: 0
    max: 24
    step: 1
  bedroomfan_timer_minutes:
    name: Keep on - Minutes
    icon: mdi:timer
    initial: 30
    min: 0
    max: 60
    step: 15
  #
  bedroomfan_air_circulation_hours:
    name: Keep off - Hours
    icon: mdi:timer
    initial: 0
    min: 0
    max: 24
    step: 1
  #
  bedroomfan_air_circulation_minutes:
    name: Keep off - Minutes
    icon: mdi:timer
    initial: 15
    min: 0
    max: 60
    step: 15
  #
  bedroomfan_air_circulation_active_for:
    name: Active for - Hours
    icon: mdi:timer
    initial: 1
    min: 0
    max: 24
    step: 1
#                           #
#####                    ####
#      Automation.yaml      #
#####                    ####
#                           #
- alias: Fan - Air Circulation turned on
  hide_entity: false  
  trigger:     
    - platform: state
      entity_id: 'input_boolean.enable_circulation'
      to: "on"
  action:
    - service: input_boolean.turn_on
      entity_id: input_boolean.enable_timer
    - service: switch.turn_on
      entity_id: switch.sonoff__room_fan    
# Circulation OFF
- alias: Fan - Air Circulation turned off
  hide_entity: false  
  trigger:     
    - platform: state
      entity_id: 'input_boolean.enable_circulation'
      to: "off"
  action:
    - service: input_boolean.turn_off
      entity_id: input_boolean.enable_timer
    - service: switch.turn_off
      entity_id: switch.sonoff__room_fan
#
- alias: Fan - all off
  hide_entity: false  
  trigger:     
    - platform: state
      entity_id: 'switch.sonoff__room_fan'
      to: "off"
  action:
    - service: input_boolean.turn_off
      entity_id: input_boolean.enable_timer
#
#
- alias: Timer on, so turn the fan on
  hide_entity: false  
  trigger:     
    - platform: state
      entity_id: input_boolean.enable_timer
      to: "on"
  action:
    - service: switch.turn_on
      entity_id: switch.sonoff__room_fan
#
- alias: Fan - Air Circulation
  hide_entity: false  
  trigger: 
    - platform: template
      value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_air_circulation_hours.state |int *3600) + (states.input_number.bedroomfan_air_circulation_minutes.state |int *60) %}true{% else %}false{% endif %}"
    - platform: template
      value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_circulation.last_updated)) >(states.input_number.bedroomfan_air_circulation_hours.state |int *3600) + (states.input_number.bedroomfan_air_circulation_minutes.state |int *60) %}true{% else %}false{% endif %}"
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: 'switch.sonoff__room_fan'
        state: "off"
      - condition: state
        entity_id: 'input_boolean.enable_circulation'
        state: "on"
  action:
    - service: switch.turn_on
      entity_id: switch.sonoff__room_fan
    - service: input_boolean.turn_on
      entity_id: input_boolean.enable_timer
#
- alias: Fan - Air Circulation Ative for x Hours
  hide_entity: false  
  trigger: 
    - platform: template
      value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_air_circulation_active_for.state |int *3600) %}true{% else %}false{% endif %}"
  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: 'input_boolean.enable_circulation'
        state: "on"
  action:
    - service: switch.turn_off
      entity_id: switch.sonoff__room_fan
    - service: input_boolean.turn_off
      entity_id: input_boolean.enable_timer
#                           #
#####                    ####
#        Groups.yaml        #
#####                    ####
#                           #
bedroomfan:
  name: Bedroom Fan
  entities:
  - switch.sonoff__room_fan
  - input_boolean.enable_timer
  - sensor.bedroom_fan_state_timer
  - input_number.bedroomfan_timer_hours
  - input_number.bedroomfan_timer_minutes
  - input_boolean.enable_circulation
  - input_number.bedroomfan_air_circulation_hours
  - input_number.bedroomfan_air_circulation_minutes
  - input_number.bedroomfan_air_circulation_active_for
#                           #
#####                    ####
#     Input_boolean.yaml    #
#####                    ####
#                           #
enable_timer:
  name: "Enable Timer"
  initial: off
  icon: mdi:robot
enable_circulation:
  name: "Enable Air Circulation"
  initial: off
  icon: mdi:robot

FYI: The “Current program” text updates every minute.

You can spicey it up and if HASS knows when you arrived home, you can set it up to auto turn on the fan for x minutes or auto turn off when you open the door, PIR sensor detection…

I bet you can set up an “old” room humidifier with this config too.

6 Likes

thanks for sharing
i tried to do a inputnumber for hours and one minutes just to turn of my fan but i dont know anything about templates can you help this is my config

sensor:
  - platform: time_date
    display_options:
      - 'date_time'
      - 'time'

input_number:
  bedroomfan_timer_hours:
    name: Keep on - Hours
    icon: mdi:timer
    initial: 0
    min: 0
    max: 24
    step: 1
  bedroomfan_timer_minutes:
    name: Keep on - Minutes
    icon: mdi:timer
    initial: 5
    min: 0
    max: 60
    step: 5


  - alias: ventilador 
    hide_entity: false  
    trigger: 
      - platform: template
        value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.fan.last_updated)) >(states.input_number.bedroomfan_air_circulation_active_for.state |int *3600) %}true{% else %}false{% endif %}"
    action:
      - service: switch.turn_off
        entity_id: switch.fan

Hello!

You have my whole config copied?
You should try and debug in the hass webui template editor. That’s the only way :slight_smile:
Piece by piece. Does it see the time sensor? Can it convert it to timestamp? Etc

I am trying this but, it’s not turning off.
Current Program reads: Turning off in 0:00:07 and then changes to 23:59:u6307 But fan doesn’t turn off

Would really appreciate your help.
Thanks.

It seems like there is no Turn off fan command after Timer finishes if Air circulation is off

action:

  • service: switch.turn_off
    entity_id: switch.fan

This is the turn off command. Whats your switch entity name?

Can I just use it as standalone timer?
Enable timer. Fan turns On. Timer ends. Fan should turn off.

All automations in the code you sent are linked to Air circulation.

I don’t see any Automation that is triggered that uses input.boolean.bedroomfan_timer_minutes/hours

I added this automation and this is the only way I could get it to work.

alias: Auto Off AC on Timer
  trigger:
  - platform: template
    value_template: '{% if (as_timestamp(strptime(states(''sensor.date__time''),''%Y-%m-%d, %H:%M'')) as_timestamp(states.input_boolean.enable_timer.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) +(states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}'
  condition:
  - condition: state
    entity_id: input_boolean.enable_timer
    state: 'on'
  action:
  - data:
      entity_id: climate.xxx_ac
      operation_mode: 'off'
    entity_id: climate.xxx_ac
    service: climate.set_operation_mode

Was something like this missing in the copy paste code you added in the post or am I doing something wrong/extra?

It was a long time ago i wrote that script, so i dont remember the exact automatio logic steps.
I think im using a diffrerent method then what you do. Theres a reason why i did how i did it.

If i enabled air circulation, i wanted it to automaticly turn on the fan (theres no circulation if it doesnt start auto start the fan too) and also turn on the “turn off counter” Look at the OP UI picture and you will understand what im saying. :slight_smile:

Logic:
User wants air circulation -> User turns on air circulation slider -> HASS says, okey, for that hass will start the “on - off loop program” -> That program first step is HASS turning on the FAN, and starting the turn off timer -> IF Turn off timer reached 0, so turn off the FAN and turn off the “Enable Timer” slider -> Program is now checking if Air circulation slider is on (yes it is), but “Enable Timer” and the FAN is off… so that means the FAN needs to turn back on if the turn on countdown timer reach 0 -> It reached 0, so lets turn the fan back on and turn the “Enable Timer” ON for turn off countdown - REPEAT (Until keep looping timer reach 0, but thats busted and repeats forever :stuck_out_tongue: )

My automation script (program) needs every part to work or it will get stuck on a step.

Heres my code again:

 - Auto-OFF      #
    #####                    ####
    #                           #
    - alias: Fan - Auto-OFF test
      hide_entity: false  
      trigger: 
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}"
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_timer.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}"
      condition:
        condition: and
        conditions:
          - condition: state
            entity_id: 'switch.sonoff__room_fan'
            state: "on"
          - condition: state
            entity_id: 'input_boolean.enable_timer'
            state: "on"
      action:
        - service: switch.turn_off
          entity_id: switch.sonoff__room_fan
        # - service: input_boolean.turn_off
          # entity_id: input_boolean.enable_timer
    #                           #
    #####                    ####
    #  Fan - Air Circulation ON #
    #####                    ####
    #                           #
    - alias: Fan - Air Circulation turned on
      hide_entity: false  
      trigger:     
        - platform: state
          entity_id: 'input_boolean.enable_circulation'
          to: "on"
      action:
        - service: input_boolean.turn_on
          entity_id: input_boolean.enable_timer
        - service: switch.turn_on
          entity_id: switch.sonoff__room_fan    
    # Circulation OFF
    - alias: Fan - Air Circulation turned off
      hide_entity: false  
      trigger:     
        - platform: state
          entity_id: 'input_boolean.enable_circulation'
          to: "off"
      action:
        - service: input_boolean.turn_off
          entity_id: input_boolean.enable_timer
        - service: switch.turn_off
          entity_id: switch.sonoff__room_fan
    #
    - alias: Fan - all off
      hide_entity: false  
      trigger:     
        - platform: state
          entity_id: 'switch.sonoff__room_fan'
          to: "off"
      action:
        - service: input_boolean.turn_off
          entity_id: input_boolean.enable_timer
    #
    #
    - alias: Timer on, so turn the fan on
      hide_entity: false  
      trigger:     
        - platform: state
          entity_id: input_boolean.enable_timer
          to: "on"
      action:
        - service: switch.turn_on
          entity_id: switch.sonoff__room_fan
    #
    - alias: Fan - Air Circulation
      hide_entity: false  
      trigger: 
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_air_circulation_hours.state |int *3600) + (states.input_number.bedroomfan_air_circulation_minutes.state |int *60) %}true{% else %}false{% endif %}"
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_circulation.last_updated)) >(states.input_number.bedroomfan_air_circulation_hours.state |int *3600) + (states.input_number.bedroomfan_air_circulation_minutes.state |int *60) %}true{% else %}false{% endif %}"
      condition:
        condition: and
        conditions:
          - condition: state
            entity_id: 'switch.sonoff__room_fan'
            state: "off"
          - condition: state
            entity_id: 'input_boolean.enable_circulation'
            state: "on"
      action:
        - service: switch.turn_on
          entity_id: switch.sonoff__room_fan
        - service: input_boolean.turn_on
          entity_id: input_boolean.enable_timer
- Auto-OFF      #
    #####                    ####
    #                           #
    - alias: Fan - Auto-OFF test
      hide_entity: false  
      trigger: 
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}"
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.input_boolean.enable_timer.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}"
      condition:
        condition: and
        conditions:
          - condition: state
            entity_id: 'switch.sonoff__room_fan'
            state: "on"
          - condition: state
            entity_id: 'input_boolean.enable_timer'
            state: "on"
      action:
        - service: switch.turn_off
          entity_id: switch.sonoff__room_fan
        # - service: input_boolean.turn_off
          # entity_id: input_boolean.enable_timer

This part of your code was missing in the previous post.

I kind of ended up adding this only. :slight_smile:

But I haven’t added this to Auto OFF command. Any reason for adding this trigger as well?:

trigger: 
        - platform: template
          value_template: "{% if (as_timestamp(strptime(states('sensor.date__time'),'%Y-%m-%d, %H:%M'))-as_timestamp(states.switch.sonoff__room_fan.last_updated)) >(states.input_number.bedroomfan_timer_hours.state |int *3600) + (states.input_number.bedroomfan_timer_minutes.state |int *60) %}true{% else %}false{% endif %}"

Amazing work!

1 Like

Glad you got it working! Sorry for the missing part.

I have no idea about the templates, looks like they return the same results… Might be a leftover from a previous version :stuck_out_tongue:

Thanks a lot. Amazing script.

Tried it but it seems like Enable air circulation doesn’t turn off automatically?
I was hoping for it to turn off after “active for hours” hours.

1 Like

Because its busted for some reason, probably a typo or logic error… Might fix it someday, or you can do it and please share it :smiley: