diff --git a/README.md b/README.md index d9d29e2..bf81965 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Every purifier covered here at a glance — how it's converted to ESPHome, its s | [Everest Air](./devices/levoit-everest-air) | Levoit | 🟢 Flash / 🔵 Add ESP | 612 m³/h | 24–56 dB | Easy | [Guide](./devices/levoit-everest-air) | [Amazon](https://amzn.to/3Q1cMB) | ✅ Tested · vent louver, PM1.0/2.5/10, Turbo | | [Sprout](./devices/levoit-sprout) | Levoit | 🟢 Flash / 🔵 Add ESP | 145 m³/h | 22–47 dB | Easy | [Guide](./devices/levoit-sprout) | [Amazon](https://amzn.to/4oAJs1n) | 🚧 WIP · white-noise audio (I2S MP3) | | [LV-PUR 131S](./devices/levoit-lv131s/) | Levoit | 🔴 Custom HW | — | — | Medium | [Guide](./devices/levoit-lv131s/) | — | Custom FW + MCU & sensor upgrade | -| [LV-PUR 131](./devices/levoit-lv131/) | Levoit | 🔴 Custom HW | — | — | Medium | [Guide](./devices/levoit-lv131/) | — | Custom FW + MCU upgrade | +| [LV-PUR 131](./devices/levoit-lv131/) | Levoit | 🔴 Custom HW | — | — | Medium | [Guide](./devices/levoit-lv131/) | — | Custom FW + temperature sensor + MCU & sensor upgrade | | [Levoit Mini](./devices/levoit-mini) | Levoit | 🔴 Custom HW | 78 m³/h | 41.8 – 53.6 dBA | Easy | [Guide](./devices/levoit-mini) | [Amazon](https://amzn.to/4acovEh) | Full custom PCB + 3D parts | | [Philips AC0650](./devices/philips-600-series) | Philips| 🔵 Add ESP | 170 m³/h | 19–49 dB | Easy | [Guide](./devices/philips-600-series) | [Amazon](https://amzn.to/4vS5Ohs) | ✅ Tested · secure boot → replace module; no AQ sensor | | [Philips AC0651](./devices/philips-600-series) | Philips| 🔵 Add ESP | 170 m³/h | 19–49 dB | Easy | [Guide](./devices/philips-600-series) | [Amazon](https://amzn.to/4elkSyg) | ✅ Tested · adds PM2.5 (PM1003) + Auto mode | @@ -136,7 +136,7 @@ The Levoit Sprout additionally uses the [levoit_audio component](./components/le ### Other Models / Levoit Projects * [Levoit LV-PUR 131S](./devices/levoit-lv131s/) – Custom Firmware + MCU & sensor upgrade + hardware hack -* [Levoit LV-PUR 131](./devices/levoit-lv131/) – Custom Firmware + MCU upgrade + hardware hack +* [Levoit LV-PUR 131](./devices/levoit-lv131/) – Custom Firmware + temperature sensor + MCU & sensor upgrade + hardware hack * [Levoit Mini](./devices/levoit-mini) – Custom PCB, 3D parts, hardware hack ### Features diff --git a/devices/README.md b/devices/README.md index af87e86..aa10f5b 100644 --- a/devices/README.md +++ b/devices/README.md @@ -11,7 +11,7 @@ Special: * [Levoit LV PUR 131s](./levoit-lv131s/) – Custom Firmware + MCU & sensor upgrade + hardware hack -* [Levoit LV PUR 131](./levoit-lv131/) – Custom Firmware + MCU upgrade + hardware hack +* [Levoit LV PUR 131](./levoit-lv131/) – Custom Firmware + temperature sensor + MCU & sensor upgrade + hardware hack * [Levoit Mini](./levoit-mini) – Custom PCB, 3D parts, hardware hack Core 200S/300S/400S and Vital100/200, only require disassembly to flash firmware (no hardware modifications needed). diff --git a/devices/levoit-lv131/README.md b/devices/levoit-lv131/README.md index 49ae351..bc04b69 100644 --- a/devices/levoit-lv131/README.md +++ b/devices/levoit-lv131/README.md @@ -2,31 +2,35 @@ # Levoit LV-PUR131 - Custom Firmware (ESPHome) -The LV-PUR131 model is very similar to the [LV-131S](../levoit-lv131s/README.md) (later called the S board / model) except it doesn't havethe wireless capabilities. +The LV-PUR131 model is very similar to the [LV-PUR131S](../levoit-lv131s/README.md) (later called the S board / model) except it doesn't have the wireless capabilities. They look identical and have mostly the same components. **Hardware Upgrades:** - MCU: Original On-Bright OB39R08A3U20SP -> ESP32-C3 Super Mini -- Sensor upgrade to PM5003 is theoretically possible and should be implemented the same way it is on the S board, but I don't have the money to buy one right now. Please make a PR if you tested whether it works or not. +- Sensor: Original PM1003 -> PM5003 + +![Whole mod](./images/whole.jpg) ## Features - WiFi on a machine that never was supposed to have it!! +- A temperature sensor. - Everything available on the S model. ## Why this works? Because we replace the old UC with one that can do wireless and levoit reused the same components between this and the wireless model. ## Interesting findings -The main differences between the models are the ones related to the microcontroller and the voltage it uses. The S board uses an ESP32 and runs on 3.3V whereas this model runs on a microcontroller that works fully on 5V - even the display is the same, thanks to which this mod is able to use the wifi icon which normally is not (I think?) used by the machine at all. The routing also changes a bit between the boards but not really by much. +The main differences between the models are the ones related to the microcontroller and the voltage it uses. The S board uses an ESP32 and runs on 3.3V whereas this model runs on a microcontroller that works fully on 5V - even the display is the same, thanks to which this mod is able to use the wifi icon which normally is not (I think?) used by the machine at all. The routing also changes a bit between the boards but not by much. ## Hardware Upgrade Project ("The Hack") ### Required Parts - Broken or working Levoit LV-PUR131 -- Any cheap ESP32 board really. A cheap chinese C3 Super Mini works fine. +- Any cheap ESP32 board really. A chinese C3 Super Mini works fine. - Wires -- 3x 10k ohm resistor -- 2x 4.7k ohm resistor -- BAT43 diode +- 1x 10k ohm resistor +- 1x 4.7k ohm resistor +- PMS5003 +- DHT22 (and the things necessary to make it work if your module doesn't have them on board) ### Required Tools - Something to cut a trace with @@ -36,7 +40,7 @@ The main differences between the models are the ones related to the microcontrol Same as the S model. ### Hack / Modify PCB -We need to force the board to behave like the S model so the S mod works here as well. To acomplish this we need to add two voltage dividers, a resistor, a diode, cut a trace, and desolder the old UC. +We need to force the board to behave like the S model so the S mod works here as well. To acomplish this we need to add a voltage divider, cut a trace, and desolder the old UC. This is what the board looks like: ![Board](./images/board.gif) @@ -51,12 +55,9 @@ This is what the finished board looks like. Sorry for the flux, I ran out of IPA ![Mod](./images/mod.png) #### Important? -- I didn't have the schottky diode on hand so I used a 1N4148 diode instead. Because of it's forward voltage I had to add another 10k resistor on the Q101's base. This part is marked in purple and is in the bottom right corner of the solder_points.jpg. The schematic does not include this part, and so shouldn't you. - The original UC is stuck in place with some kind of glue. You might have to apply a bit of force to get it to move. +- The PMS5003 placement is the same as on the S model, but it does not seem to be the most optimal. I think my module has airflow issues. +- I glued the DHT22 to the outside wall of the space between the air quality sensor and the fan. The temperature readings seem correct, there's only around a .2C difference compared to a sensor I have hanging on a wall which is more than good enough for this kind of sensors. I'll think about getting a more precise one and messing around with the placement as the humidity reading are way off. ### How, why, etc. -The board is designed to work on 5V only. Our ESP32 runs on 3.3V and if we feed it's GPIO 5V it's gonna blow up. Every time there is a risk of 5V going into out new controller we need to somehow convert it to ~3.3V. This is why the voltage dividers are needed, and this is also why we need to cut the trace pulling up the TM1628's lines to 5V and replace it with 3.3V as well. - -## Notes - -- There still is one GPIO left free on the board. Somebody, please put an LED strip in the vent and share what it looks like. +The board is designed to work on 5V only. Our ESP32 runs on 3.3V and if we feed it's GPIO 5V it's gonna blow up. Every time there is a risk of 5V going into out new controller we need to somehow convert it to ~3.3V. This is why the voltage divider is needed, and this is also why we need to cut the trace pulling up the TM1628's lines to 5V and replace it with a 3.3V pullup as well. diff --git a/devices/levoit-lv131/images/mod.png b/devices/levoit-lv131/images/mod.png index d4d38bc..efd90ec 100644 Binary files a/devices/levoit-lv131/images/mod.png and b/devices/levoit-lv131/images/mod.png differ diff --git a/devices/levoit-lv131/images/schematics.png b/devices/levoit-lv131/images/schematics.png index e65009a..f0d84a4 100644 Binary files a/devices/levoit-lv131/images/schematics.png and b/devices/levoit-lv131/images/schematics.png differ diff --git a/devices/levoit-lv131/images/solder_points.jpg b/devices/levoit-lv131/images/solder_points.jpg index edebb13..610c382 100644 Binary files a/devices/levoit-lv131/images/solder_points.jpg and b/devices/levoit-lv131/images/solder_points.jpg differ diff --git a/devices/levoit-lv131/images/whole.jpg b/devices/levoit-lv131/images/whole.jpg new file mode 100644 index 0000000..4929bef Binary files /dev/null and b/devices/levoit-lv131/images/whole.jpg differ diff --git a/devices/levoit-lv131/levoit-lv131-c3.yaml b/devices/levoit-lv131/levoit-lv131-c3.yaml index a686345..6d962ed 100644 --- a/devices/levoit-lv131/levoit-lv131-c3.yaml +++ b/devices/levoit-lv131/levoit-lv131-c3.yaml @@ -1,5 +1,4 @@ # Board: ESP32-C3 Super Mini (Generic) -# This is basically the LV-131S definition with just a few changes. The same 500khz notice applies here too. esphome: name: lv-pur131 @@ -33,7 +32,7 @@ wifi: password: !secret wifi_password ap: ssid: LV-PUR131 Fallback Hotspot - password: "Litwo!OjczyznoMoja!TyJestesJakZdrowie." + password: !secret ap_password passive_scan: true on_connect: - globals.set: @@ -55,7 +54,7 @@ spi: spi_device: id: spidev cs_pin: GPIO03 #D1 - data_rate: 200khz # use 500khz is possible esphome 2026.01+ required! + data_rate: 500khz spi_mode: 0 bit_order: lsb_first @@ -87,6 +86,12 @@ uart: id(btn_run_check)->stop(); id(btn_run_check)->execute(); + # PMS5003 + - id: uart_sensor + rx_pin: GPIO08 #D8 + tx_pin: GPIO09 #D9 + baud_rate: 9600 + globals: - id: display_bits type: uint8_t[14] @@ -135,15 +140,6 @@ switch: optimistic: true entity_category: CONFIG icon: "mdi:volume-high" - # active low heater control switch - - platform: gpio - pin: - number: GPIO08 #D8 - mode: OUTPUT - id: sensor_heater - inverted: true - restore_mode: ALWAYS_OFF - internal: true fan: - platform: template @@ -159,10 +155,8 @@ fan: - script.execute: update_fan_speed on_turn_on: - script.execute: fan_turn_on - - switch.turn_on: sensor_heater # turn on the sensor heater when the fan starts on_turn_off: - script.execute: fan_turn_off - - switch.turn_off: sensor_heater # turn off the sensor heater when the fan stops on_preset_set: - script.execute: fan_update_preset on_speed_set: @@ -221,40 +215,30 @@ number: id(timer_text).publish_state(buf); sensor: - # stock PM1003 - # using id sensor_pm2_5 to references - - platform: pulse_width - name: 'PM10' - update_interval: 15s - id: sensor_pm2_5 - state_class: measurement - device_class: pm10 - icon: mdi:chemical-weapon - unit_of_measurement: 'µg/m³' - accuracy_decimals: 0 - pin: - number: GPIO07 #D5 - inverted: true - mode: - input: true - on_value: - - script.execute: update_fan_speed - filters: - - round_to_multiple_of: 0.01 - - calibrate_linear: - method: exact - datapoints: - - 0.0 -> 0.0 - - 0.01 -> 0.0 - - 0.1 -> 140 - - 0.15 -> 210 - - 0.20 -> 285 - - 0.25 -> 300 - - 1.1 -> 300 - - round_to_multiple_of: 1 - - sliding_window_moving_average: - window_size: 3 - send_every: 1 + - platform: pmsx003 + type: PMSX003 + uart_id: uart_sensor + id: pms5003_hub + pm_1_0: + name: "PM <1.0µm" + pm_2_5: + name: "PM <2.5µm" + id: sensor_pm2_5 + on_value: + - script.execute: update_fan_speed + pm_10_0: + name: "PM <10.0µm" + update_interval: 60s + + - platform: dht + id: dht_sensor + pin: GPIO07 #D5 + temperature: + name: "Purifier Room Temperature" + humidity: + name: "Purifier Room Humidity" + model: DHT22 + update_interval: 60s - platform: template name: "AQI - PM10" @@ -464,6 +448,23 @@ button: icon: mdi:timer-outline on_press: - script.execute: cycle_timer + + - platform: template + name: "Refresh All Sensors" + id: refresh_sensors_btn + icon: "mdi:refresh" + on_press: + then: + - logger.log: "Manual sensor refresh triggered" + - component.update: dht_sensor + - script.execute: play_beep + - lambda: |- + // trick the PMS5003 into thinking an update is overdue + id(pms5003_hub)->set_update_interval(30005); + - delay: 35s + - lambda: |- + id(pms5003_hub)->set_update_interval(60000); + - logger.log: "PMS5003 manual refresh completed; returning to sleep." interval: - interval: 100ms @@ -526,10 +527,8 @@ script: case 3: speed = 0.8f; break; default: speed = 0.0f; break; } - //special speed for sleep if(ps=="Sleep") speed = 0.33f; - //if auto and clean air, turn off pwm, keep fan on! if(ps=="Auto" && id(sensor_pm2_5).state<=1.0f) speed = 0.0f; } @@ -551,10 +550,9 @@ script: then: - lambda: |- auto ps = id(fan_lv131).get_preset_mode(); - if (ps =="Auto"){ + if (ps == "Auto"){ ESP_LOGI("TS","from auto speed"); auto aqi = id(aqi_pm10).state; - //only if different!!!!! uint8_t new_speed = 1; if(aqi == 0.0) new_speed = 1; if(aqi == 1.0) new_speed = 1; @@ -575,7 +573,7 @@ script: then: - lambda: |- auto ps = id(fan_lv131).get_preset_mode(); - if(id(fan_lv131).state && ps==""){ + if(id(fan_lv131).state && ps == ""){ auto call = id(fan_lv131).turn_on(); call.set_speed(2); call.perform();