ESPHome inside Ikea Air Purifier Template Help

Hi, first post did some searching but need some help or pointers.

As the subject says I put an ESPHome inside of an Ikea AIr Purifier that I want to use with my 3D printer. Along with the ESPHome there is an SGP41 VoC sensor, DC power meter and a GPIO switch to trigger the only button that is controlled by a virtual switch in the config.yaml. When the switch is triggered it “presses the button” for 200ms and shuts off. As it cycles through speeds I see the volts, amps and watts consumed at each setting. All the hardware works perfectly fine. The button starts at “Off”, when you I trigger the virtual switch it goes to low then med then high and back to off. I want to use wattage ranges to determine what the speed is at or if its off.

I have been trying to figure out using the fan template to control this with off, low,med,high like a ceiling fan. I have seen many examples including: https://community.home-assistant.io/t/king-of-fans-mr101z-missing-max-setting/267131/37

I get nothing at all showing speed in the templage. I am really new to using ESPHome and configuring an ESP8266 or ESP32. I first set up a Garage Door opener that reads the signal from the magnetic rail sensors to determine if its open or closed and trigger then door open/ close including a template with the up arrow, stop button and down arrow which all works so I have had some success.

Perhaps the way to do this is via code in the ESP8266 but I have not done anything like that yet?

Right now I am stuck trying to understand the different parts of the template value_template, percentage_template and the relationships therein. I have a script that I built from the above link along with the virtual device but like I said, nothing happens when I use the virtual switch or the one from the ESPHome. It always says its off.

Anyone have any guidance or pointers such as other posts to read etc?

Ultimately I plan to use NodeRed to control fan speed based on VoC sensor levels which won’t need any of this but I would like to be able to press medium from the cirtual button have it trigger the button twice from off to medium.

Thanks in advance!

config.yaml stuff I have tried, no doubt there are mistakes:

script:
  set_air_purifier_speed:
    fields:
      percentage:
        description: The percentage that should be set.
        example: '0'
    sequence:
    - choose:
      - conditions:
        - condition: template
          value_template: '{{ percentage == 0 }}'
        sequence:
        - service: fan.turn_off
          target:
            entity_id: fan.air_purifier_3d_printer
      - conditions:
        - condition: template
          value_template: '{{ percentage > 0 }}'
        sequence:
        - service: number.set_value
          target:
            entity_id: number.air_purifier_3d_printer_favorite_level
          data:
            value: '{{ ((percentage - (100/3 | round(0))) * 3/100) | round(0)}}'
        - service: fan.set_preset_mode
          target:
            entity_id: fan.air_purifier_3d_printer
          data:
            preset_mode: Favorite
        - service: fan.turn_on
          target:
            entity_id: fan.air_purifier_3d_printer
    mode: single
  turn_air_purifier_on:
    sequence:
    - choose:
      - conditions:
        - condition: template
          value_template: '{{ state_attr(''fan.air_purifier_3d_printer'', ''percentage'') == 0}}'
        sequence:
        - service: fan.set_percentage
          target:
            entity_id: fan.air_purifier_3d_printer
          data:
            percentage: 7
      - conditions:
        - condition: template
          value_template: '{{ state_attr(''fan.air_purifier_3d_printer'', ''percentage'') > 0 }}'
        sequence:
        - service: fan.set_preset_mode
          target:
            entity_id: fan.air_purifier_3d_printer
          data:
            preset_mode: Favorite
        - service: fan.turn_on
          data:
            entity_id: fan.air_purifier_3d_printer
    mode: single


fan:
  - platform: template
    fans:
      air_purifier_3d_printer:
        unique_id: "air_purifier_3d_printer"
        friendly_name: "3D Printer Air Purifier"
        value_template: "{{ states('fan.air_purifier_3d_printer') }}"
        percentage_template: >
          {{ ((states('number.air_purifier_3d_printer_favorite_level') | int + 1) * 100/3) | round(0) }}
        turn_on:
          service: script.turn_air_purifier_on
        turn_off:
          service: fan.turn_off
          data:
            entity_id: fan.air_purifier_3d_printer
        set_percentage:
          service: script.set_air_purifier_speed
          data_template:
            percentage: "{{ percentage }}"
        speed_count: 3

Answering my own question, the following is in configuration.yaml:

fan:
  - platform: template
    fans:
      air_purifier_3d_printer:
        friendly_name: "3D Printer Air Purifier"
        entity_id: "fan.air_purifier_3d_printer"
        value_template: >
           {{ states('number.3d_printer_air_purifier_3d_printer_air_purifier_fan_speed') | float(0) > 0 }}
        speed_count: 3
        percentage_template: >
          {{ ((states('number.3d_printer_air_purifier_3d_printer_air_purifier_fan_speed') | int) * 33) }}
        turn_on:
          service: switch.turn_on
          entity_id: switch.3d_printer_air_purifier_3d_printer_air_purifier_button
        turn_off:
          service: script.air_purifier_3d_printer_speed
          data:
            percentage: 0
        set_percentage:
          service: script.air_purifier_3d_printer_speed
          data:
            percentage: "{{ percentage }}"

Using the built in script editor I created the script:

sequence:
  - repeat:
      while:
        - condition: and
          conditions:
            - condition: template
              value_template: >-
                {{((states('number.3d_printer_air_purifier_3d_printer_air_purifier_fan_speed')
                | int) !=  (percentage/33)|int) }}
            - condition: template
              value_template: "{{ repeat.index <= 10 }}"
      sequence:
        - action: switch.turn_on
          metadata: {}
          data: {}
          target:
            entity_id: switch.3d_printer_air_purifier_3d_printer_air_purifier_button
        - delay: "00:00:04"

And the ESPHOME Code:

esphome:
  name: 3d-printer-air-purifier
  friendly_name: 3D Printer Air Purifier

esp8266:
  board: esp01_1m

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "<REDACTED>"

ota:
  - platform: esphome
    password: "<REDACTED>"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "3D-Printer-Air-Purifier"
    password: "<REDACTED>"

captive_portal:
    
i2c:
  sda: GPIO4
  scl: GPIO5
  scan: true
  id: bus_a

sensor:
  - platform: sgp4x
    voc:
      name: "3D Printer VOC Index"
    nox:
      name: "3D Printer NOx Index"
    compensation:
      humidity_source: sht41_humidity
      temperature_source: sht41_temp
    update_interval: 30s

  - platform: sht4x
    temperature:
      force_update: true
      id: sht41_temp
      name: "3D Printer Temperature"
    humidity:
      force_update: true
      id: sht41_humidity
      name: "3D Printer Humidity"
    update_interval: 60s

  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
    current:
      filters:
        - delta: .5
      name: "3D Printer Air Purifier Current"
    power:
      filters:
        - delta: .5
      name: "3D Printer Air Purifier Watts"
      on_value_range: 
        - below: .5
          then:
            - number.set:
                id: airpurifier3dprinterfanspeed
                value: 0
        - above: .5
          below: 2.5
          then:
            - number.set: 
                id: airpurifier3dprinterfanspeed
                value: 1
        - above: 2.6
          below: 3.8
          then:
            - number.set: 
                id: airpurifier3dprinterfanspeed
                value: 2
        - above: 4
          then:
            - number.set:
                id: airpurifier3dprinterfanspeed
                value: 3
    bus_voltage:
      filters:
        - delta: .5
      name: "3D Printer Air Purifier Bus Voltage"
    shunt_voltage:
      filters:
        - delta: .5
      name: "3D Printer Air Purifier Shunt Voltage"
    max_voltage: 32.0V
    max_current: 3.2A
    update_interval: 1s
    
switch:
  - platform: gpio
    pin: GPIO14
    id: airpurifier3dprinter
    icon: mdi:button-pointer
    name: "3D Printer Air Purifier Button"
    on_turn_on:
    - delay: 200ms
    - switch.turn_off: airpurifier3dprinter

number:
  - platform: template
    name: "3D Printer Air Purifier Fan Speed"
    id: airpurifier3dprinterfanspeed
    step: 1
    min_value: 0
    max_value: 3
    mode: SLIDER
    optimistic: true

The ESPHome code creates a slider that uses the wattages consumed to determine the current speed. There can be some lag in update to accurate value because sometimes the wattage jumps above the range as expected on spin up and then settles on the typical running wattage.

That slider position change sets the virtual switch percentage defined in the configuration.yaml along with the fact that it is non-zero determining if it is on. Further the turn on/turn off actions are defined.

Finally the script is used when setting percentage with the virtual switch to control the fan in a way to repeat the button press for the esphomes toggle button until the set percentage is the actual percentage the device is at waiting 4 seconds between button pushes giving wattage to settle and update the slider. It has a safety of 10 repeats before it quits so it doesnt end up in an endless loop.

The ESPHome device looks like this:

The Virtual switch like any fan switch: