diff --git a/src/content/docs/components/sensor/images/pm1003.png b/src/content/docs/components/sensor/images/pm1003.png
new file mode 100644
index 0000000000..5a0b12d391
Binary files /dev/null and b/src/content/docs/components/sensor/images/pm1003.png differ
diff --git a/src/content/docs/components/sensor/images/pm1003_connector.png b/src/content/docs/components/sensor/images/pm1003_connector.png
new file mode 100644
index 0000000000..6b6c6bf060
Binary files /dev/null and b/src/content/docs/components/sensor/images/pm1003_connector.png differ
diff --git a/src/content/docs/components/sensor/images/pm1006.png b/src/content/docs/components/sensor/images/pm1006.png
new file mode 100644
index 0000000000..fb2ec59cdf
Binary files /dev/null and b/src/content/docs/components/sensor/images/pm1006.png differ
diff --git a/src/content/docs/components/sensor/images/pm1006_connector.png b/src/content/docs/components/sensor/images/pm1006_connector.png
new file mode 100644
index 0000000000..ba927ab509
Binary files /dev/null and b/src/content/docs/components/sensor/images/pm1006_connector.png differ
diff --git a/src/content/docs/components/sensor/pm100x.mdx b/src/content/docs/components/sensor/pm100x.mdx
new file mode 100644
index 0000000000..0aa8d2bff1
--- /dev/null
+++ b/src/content/docs/components/sensor/pm100x.mdx
@@ -0,0 +1,184 @@
+---
+description: "Instructions for setting up PM1003, PM1006 and PM1006K Particulate matter sensors, such as in the IKEA VINDRIKTNING or Levoit Air Purifiers"
+title: "PM100X Particulate Matter Sensors"
+---
+
+import { Image } from 'astro:assets';
+import Figure from '@components/Figure.astro';
+import pm1003Img from './images/pm1003.png';
+import pm1006Img from './images/pm1006.png';
+import pm1003ConnectorImg from './images/pm1003_connector.png';
+import pm1006ConnectorImg from './images/pm1006_connector.png';
+import APIRef from '@components/APIRef.astro';
+
+The PM1003, PM1006, and PM1006K particulate matter sensors are supported by ESPHome via two separate platforms:
+
+- **`pm100x_uart`** — UART-based, active polling at 9600 baud. Supports PM1003, PM1006, and PM1006K with PM1.0, PM2.5, and PM10.0 sensors.
+- **`pm100x_pwm`** — PWM duty-cycle based, requires a GPIO input pin. Reports PM2.5 via duty-cycle percentage. Supports PM1003 and PM1006K.
+
+| PM1003 | PM1006 and PM1006K |
+| --- | --- |
+| | |
+
+**Example configuration:**
+
+UART — PM1006K with PM1.0, PM2.5, PM10.0
+
+```yaml
+uart:
+ rx_pin: GPIO22
+ tx_pin: GPIO21
+ baud_rate: 9600
+
+sensor:
+ - platform: pm100x_uart
+ model: pm1006k
+ pm_1_0:
+ name: "PM1.0"
+ pm_2_5:
+ name: "PM2.5"
+ pm_10_0:
+ name: "PM10.0"
+```
+
+PWM — PM1003, PM2.5 only
+
+```yaml
+sensor:
+ - platform: pm100x_pwm
+ model: pm1003
+ pm_2_5:
+ name: "PM2.5"
+ pwm:
+ name: "PM2.5 Duty Cycle"
+ pin:
+ number: GPIO27
+ inverted: true
+```
+
+## Configuration variables: `pm100x_uart`
+
+- **model** (*Optional*): PM100x model selection. One of `pm1003`, `pm1006`, `pm1006k`. Defaults to `pm1003`.
+- **pm_2_5** (*Optional*): PM2.5 concentration in µg/m³. All options from [Sensor](/components/sensor).
+- **pm_1_0** (*Optional*): PM1.0 concentration in µg/m³. Only supported on `pm1006k`. All options from [Sensor](/components/sensor).
+- **pm_10_0** (*Optional*): PM10.0 concentration in µg/m³. Only supported on `pm1006k`. All options from [Sensor](/components/sensor).
+- **startup_delay** (*Optional*, [Time](/guides/configuration-types#time)): Time to wait after boot before publishing measurements. Defaults to `15s`.
+- **update_interval** (*Optional*, [Time](/guides/configuration-types#time)): Interval between measurement requests. Set to `0s` to disable active requests (passive/sniffer mode). Defaults to `never` (one-shot on boot).
+- **uart_id** (*Optional*, [ID](/guides/configuration-types#id)): ID of the UART bus if multiple are configured.
+
+## Configuration variables: `pm100x_pwm`
+
+- **model** (*Optional*): PM100x model selection. One of `pm1003`, `pm1006k`. Defaults to `pm1003`.
+- **pm_2_5** (*Optional*): PM2.5 concentration in µg/m³. All options from [Sensor](/components/sensor).
+- **pwm** (**Required**): PWM duty-cycle sensor configuration.
+ - **pin** (**Required**, GPIO input): GPIO pin connected to the sensor's PWM output (P1). Uses the ESPHome GPIO input pin schema.
+ - **update_interval** (*Optional*, [Time](/guides/configuration-types#time)): Duty-cycle polling interval. Defaults to `30s`.
+ - All other options from [Sensor](/components/sensor).
+- **startup_delay** (*Optional*, [Time](/guides/configuration-types#time)): Time to wait after boot before publishing measurements. Defaults to `15s`.
+
+## Model information
+
+| Model | Example devices | Measurement range | Interfaces | Measures |
+| --- | --- | --- | --- | --- |
+| PM1003 | Levoit air purifiers (Vital100s, LV-131PUR) | 0–500 µg/m³ | UART, PWM | PM2.5 |
+| PM1006 | IKEA VINDSTYRKA | 0–1000 µg/m³ | UART | PM2.5 |
+| PM1006K | — | 0–1000 µg/m³ | UART, PWM | PM1.0, PM2.5, PM10.0 |
+
+- **Supply voltage**: 5V
+- **Signal level**: 4.5V TTL (UART and PWM)
+
+## Wiring
+
+PM100x devices communicate via UART at 9600 baud or expose a PWM duty-cycle output on P1. Choose one method (UART or PWM).
+
+RX/TX and PWM are 4.5V TTL.
+Use a level shifter (e.g: BSS138) for UART for 3.3V ESP boards.
+For PWM, a 10k/20k resistor divider to GND is required to bring the signal to 3.3V.
+
+```text
+PM100X P1----[10k]----+----> ESP GPIO (3.3V)
+ |
+ [20k]
+ |
+ GND
+```
+
+## PM1003 Pinout
+
+
+
+| PM1003 pin | ESP pin | Notes |
+| --- | --- | --- |
+| 1 GND | GND | Ground. |
+| 2 TX | RX | UART data from PM1003 to ESP. |
+| 3 VDD | 5V | Power input. |
+| 4 P1 | Any GPIO input | PWM duty-cycle output for PM2.5. |
+| 5 RX | TX | UART data from ESP to PM1003. |
+
+## PM1006/PM1006K Pinout
+
+
+
+| PM1006(K) pin | ESP pin | Notes |
+| --- | --- | --- |
+| 1 GND | GND | Ground. |
+| 2 VDD | 5V | Power input. |
+| 3 RX | TX | UART data from ESP to PM1006/K. |
+| 4 TX | RX | UART data from PM1006/K to ESP. |
+
+:::note
+Pin 4 on the PM1006K outputs PWM if no UART commands are received after startup. This may also apply to the PM1006 (not verified).
+:::
+
+## Additional examples
+
+UART — PM1006 (PM2.5 only)
+
+```yaml
+uart:
+ rx_pin: GPIO22
+ tx_pin: GPIO21
+ baud_rate: 9600
+
+sensor:
+ - platform: pm100x_uart
+ model: pm1006
+ pm_2_5:
+ name: "PM2.5"
+```
+
+UART — passive IKEA VINDRIKTNING
+
+In common usage with the IKEA VINDRIKTNING still controlling the PM1006 sensor, set `update_interval: 0s` to disable active requests. The ESPHome device will passively pick up measurements requested by the VINDRIKTNING MCU.
+
+In this case you only need the `rx_pin` configured in UART.
+
+The implementation was inspired by [esp8266-vindriktning-particle-sensor](https://github.com/Hypfer/esp8266-vindriktning-particle-sensor); you can also see the pinout there.
+However, we recommend mounting your ESP below the fan (which blows out the front) so you do not obstruct the airflow.
+[This discussion thread on the HA forum](https://community.home-assistant.io/t/ikea-vindriktning-air-quality-sensor/324599) has several examples of how people have connected their ESP device to the IKEA sensor.
+
+```yaml
+uart:
+ rx_pin: GPIO22
+ baud_rate: 9600
+
+sensor:
+ - platform: pm100x_uart
+ model: pm1006
+ update_interval: 0s
+ pm_2_5:
+ name: "PM2.5"
+```
+
+## Notes
+
+- `pm1006` does not support PWM.
+- `pm_1_0` and `pm_10_0` are only available on `pm1006k` and require UART (`pm100x_uart`).
+- The `pwm` sensor measures duty-cycle percentage internally; the `pm_2_5` sensor publishes the converted µg/m³ value.
+
+## See also
+
+- [Sensor Filters](/components/sensor#sensor-filters)
+- [UART Component](/components/uart)
+-
+- [ESPHome Levoit Air Purifiers Project](https://github.com/tuct/esphome-projects/tree/main/projects/free-levoit)