Living in a college dorm is an experience everyone should go through. Nothing screams "college" more than the sickness you seem to constantly have and the loud noises continuing all throughout the night.
I thought that I could do something about the sickness part though, and read about how everyone recommends to get an air purifier with a HEPA filter. However, I wanted it to be controllable through Home Assistant, without the use of any third party cloud services.
Originally, I looked for Tuya-compatible air purifiers, as they could be flashed with ESPHome to talk to the Tuya MCU over UART, but they didn't get very good reviews. I found the Levoit Core 300S purifier on Amazon, and it seemed like a good match after scouring the FCC docs and seeing that it used an ESP32.

I setup the purifier through the regular "VeSync" app that was provided with the unit and started to dump the communications between the ESP32 and the purifier's main control MCU. Turns out it was just standard 8N1 115200-baud UART.

The packets followed a regular format, and I was able to write a custom ESPHome integration for the purifier. It may work on other models with some modifications for the different features.

ESPHome Configuration
The full configuration file for the air purifier is below. It will automatically create all necessary entities in Home Assistant.
esphome: name: "levoit-air-purifier" friendly_name: "levoit-air-purifier" esp32: board: esp32dev framework: type: esp-idf sdkconfig_options: CONFIG_FREERTOS_UNICORE: y external_components: - source: github://acvigue/esphome@levoit-core300s components: [levoit] logger: baud_rate: 115200 # Enable Home Assistant API api: encryption: key: "..." wifi: networks: - ssid: !secret wifi_ssid password: !secret wifi_password ap: ssid: "Levoit-Core300S Fallback Hotspot" password: !secret ap_password captive_portal: uart: tx_pin: GPIO17 rx_pin: GPIO16 baud_rate: 115200 levoit: id: levoit1 fan: - platform: levoit name: Levoit Purifier sensor: # Uptime sensor. - platform: uptime name: Uptime # WiFi Signal sensor. - platform: wifi_signal name: WiFi Signal update_interval: 60s # PM2.5 sensor - platform: levoit pm_2_5: name: PM2.5 air_quality: name: Air Quality Index switch: - platform: levoit display_lock: name: "Display Lock" display_on: name: "Display On" power: name: "Master Power" select: - platform: levoit fan_mode: name: "Fan Mode" auto_mode: name: "Auto Mode"yaml
