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