devices.esphome.io
BlitzHome BH-AP1
BlitzHome BH-AP1
Device Type: miscElectrical Standard: euBoard: esp8266Difficulty: Soldering required, 4/5
General Notes
These devices run a Tuya TYWE3S module which needs flashing. Flashing and disassembly instuctions can be found here.
The BlitzWolf BW-AP1 looks awfully similiar, probably the same device, so it's possible it's compatible as well.
GPIO Pinout
| Pin | Function | 
|---|---|
| GPIO1 | UART TX | 
| GPIO3 | UART RX | 
Configuration
There are two options:
In the first option, the device is presented as a select entity, with states OFF, Auto, Fan 1, Fan 2, Sleep.
Everything is presented in one entity, no dummy output needed. This is more similar to the controls on the device, which cycles through these options, there isn't a separate control for mode and fan speed.
The second is presenting the device as a fan with states OFF, Speed 1, Speed 2. The modes (Auto, Manual, Sleep) can be accessed by an additional select, because right now, Home Assistant does not support custom speed for fans.
In this mode when modes Auto or Sleep is selected the fan entity will display Speed 1 which is not necessarily true. Also for example if you have Sleep selected, you cannot change to Speed 1, because it is already selected. You have to change to mode to Manual instead, which can make writing automations difficult.
Because there is not a template fan, or template output in esphome, I used a dummy pwm output for the fan on GPIO4 which is not used. There is an option to change this by writing a custom output component for this, but it's probalby not worth the work.
You can choose between the two, I prefer the first method with the select, but if you insist to have the device presented as a fan entity, you can do that as well.
Configuration as select entity
substitutions:  name: air-purifier  devicename: Air Purifier
esphome:  name: ${name}  comment: ${devicename}
wifi:  ssid: !secret wifi_ssid  password: !secret wifi_password  ap:
captive_portal:
# Enable Home Assistant APIapi:  encryption:    key: !secret esphome_encryption_key
# Enable OTA updatesota:  safe_mode: true  password: !secret esphome_wifi_pass  esp8266:  board: esp01_1m
logger:  baud_rate: 0
uart:  rx_pin: GPIO3  tx_pin: GPIO1  baud_rate: 9600
tuya:  id: tuyadevice  on_datapoint_update:    - sensor_datapoint: 22      datapoint_type: enum      then:        - lambda: |-            if (x == 0) {              id(air_quality).publish_state("Excellent");            } else if (x == 1) {              id(air_quality).publish_state("Good");            } else if (x == 2) {              id(air_quality).publish_state("Poor");            }    - sensor_datapoint: 1      datapoint_type: bool      then:        - lambda: |-            if (!x) {              id(purifier).publish_state("OFF");            }    - sensor_datapoint: 3      datapoint_type: enum      then:        - lambda: |-            switch (x) {              case 0:                id(purifier).publish_state("Sleep");                break;              case 1:                id(purifier).publish_state("Auto");                break;              case 2:                if (id(tuya_fan).state == 0) {                  id(purifier).publish_state("Fan 1");                } else if (id(tuya_fan).state == 1) {                  id(purifier).publish_state("Fan 2");                }                break;            }    - sensor_datapoint: 4      datapoint_type: enum      then:        - lambda: |-            if (id(tuya_mode).state == 2) {              if (x == 0) {                id(purifier).publish_state("Fan 1");              } else if (x == 1) {                id(purifier).publish_state("Fan 2");              }            }
sensor:  - platform: tuya    name: ${devicename} PM2.5    sensor_datapoint: 2    device_class: PM25
  - platform: tuya    name: ${devicename} Filter Life    sensor_datapoint: 5    unit_of_measurement: "%"
text_sensor:  - platform: template    name: ${devicename} Air Quality    id: air_quality
button:  - platform: template    name: ${devicename} Filter Reset    entity_category: config    on_press:      - lambda: |-          id(tuyadevice).set_boolean_datapoint_value(11,1);
select:  - platform: template    name: ${devicename}    id: purifier    optimistic: true    options:      - "OFF"      - "Auto"      - "Fan 1"      - "Fan 2"      - "Sleep"    on_value:      then:        - lambda: |-            if (x == "OFF") {              if (id(tuya_power).state) {                id(tuyadevice).set_boolean_datapoint_value(1,false);              }            } else if (x == "Auto") {              if (!id(tuya_power).state) {                id(tuyadevice).set_boolean_datapoint_value(1,true);                delay(1);              }              id(tuyadevice).set_enum_datapoint_value(3,1);            } else if (x == "Fan 1") {              if (!id(tuya_power).state) {                id(tuyadevice).set_boolean_datapoint_value(1,true);                delay(1);              }              if (id(tuya_mode).state != 2) {                id(tuyadevice).set_enum_datapoint_value(3,2);                delay(1);              }              id(tuyadevice).set_enum_datapoint_value(4,0);            } else if (x == "Fan 2") {              if (!id(tuya_power).state) {                id(tuyadevice).set_boolean_datapoint_value(1,true);                delay(1);              }              if (id(tuya_mode).state != 2) {                id(tuyadevice).set_enum_datapoint_value(3,2);                delay(1);              }              id(tuyadevice).set_enum_datapoint_value(4,1);            } else if (x == "Sleep") {              if (!id(tuya_power).state) {                id(tuyadevice).set_boolean_datapoint_value(1,true);                delay(1);              }              id(tuyadevice).set_enum_datapoint_value(3,0);            }  - platform: tuya    name: ${devicename} Countdown    enum_datapoint: 19    optimistic: true    options:      0: "OFF"      1: "1 hour"      2: "2 hours"      3: "4 hours"      4: "8 hours"
switch:  - platform: tuya    id: tuya_power    switch_datapoint: 1
number:  - platform: tuya    id: tuya_mode    number_datapoint: 3    min_value: 0    max_value: 2    step: 1  - platform: tuya    id: tuya_fan    number_datapoint: 4    min_value: 0    max_value: 1    step: 1Configuration as fan entity
substitutions:  name: air-purifier  devicename: Air Purifier
esphome:  name: ${name}  comment: ${devicename}
wifi:  ssid: !secret wifi_ssid  password: !secret wifi_password  ap:captive_portal:
# Enable Home Assistant APIapi:  encryption:    key: !secret esphome_encryption_key
# Enable OTA updatesota:  safe_mode: true  password: !secret esphome_wifi_pass  esp8266:  board: esp01_1m
logger:  baud_rate: 0
uart:  rx_pin: GPIO3  tx_pin: GPIO1  baud_rate: 9600
tuya:  id: tuyadevice  on_datapoint_update:    - sensor_datapoint: 22      datapoint_type: enum      then:        - lambda: |-            if (x == 0) {              id(air_quality).publish_state("Excellent");            } else if (x == 1) {              id(air_quality).publish_state("Good");            } else if (x == 2) {              id(air_quality).publish_state("Poor");            }    - sensor_datapoint: 1      datapoint_type: bool      then:        - lambda: |-            if (x) {              id(fan1).turn_on().perform();            } else {              id(fan1).turn_off().perform();            }    - sensor_datapoint: 4      datapoint_type: enum      then:        - lambda: |-            if (x == 1) {              if (id(fan1).speed != 2) {                auto call = id(fan1).turn_on();                call.set_speed(2);                call.perform();              }            } else if (x == 0) {              if (id(fan1).speed != 1) {                auto call = id(fan1).turn_on();                call.set_speed(1);                call.perform();              }            }
fan:  - platform: speed    output: dummy_pwm    name: ${devicename}    speed_count: 2    id: fan1    on_turn_on:      - lambda: |-          id(tuyadevice).set_boolean_datapoint_value(1,true);    on_turn_off:      - lambda: |-          id(tuyadevice).set_boolean_datapoint_value(1,false);    on_speed_set:      - lambda: |-          if (id(fan1).speed == 1) {            id(tuyadevice).set_enum_datapoint_value(4,0);          } else if (id(fan1).speed == 2) {            id(tuyadevice).set_enum_datapoint_value(4,1);          }
sensor:  - platform: tuya    name: ${devicename} PM2.5    sensor_datapoint: 2    device_class: PM25
  - platform: tuya    name: ${devicename} Filter Life    sensor_datapoint: 5    unit_of_measurement: "%"
text_sensor:  - platform: template    name: ${devicename} Air Quality    id: air_quality
button:  - platform: template    name: ${devicename} Filter Reset    entity_category: config    on_press:      - lambda: |-          id(tuyadevice).set_boolean_datapoint_value(11,1);
select:  - platform: tuya    name: ${devicename} Countdown    enum_datapoint: 19    optimistic: true    options:      0: "OFF"      1: "1 hour"      2: "2 hours"      3: "4 hours"      4: "8 hours"    - platform: tuya    name: ${devicename} Mode    enum_datapoint: 3    optimistic: true    options:      0: "Sleep"      1: "Auto"      2: "Manual"
output:  - platform: esp8266_pwm    pin: GPIO4    id: dummy_pwm