Extending the life span of the PMS5003 sensor

Recently, I have read an article about the lifespan of the PMS5003 sensor. It uses laser technology to measure the concentration of particulate matter in the air. This laser light has life span of 30.000 hours, which is about 3.5 years. In this article, a solution was described to extend the life span of the PMS5003 sensor by enabling the device for 20 seconds every two minutes. This would result in an extended lifespan of around 18 years.

Wire 3 of the PMS 50003 sensor is called the SET wire, which could be used to enable and disable the sensor (high voltage to enable and low voltage to enable). By connecting this wire to one of the Data connections of the ESP module, the switch could be triggered every two minutes in ESPHome by using the following code:

switch:
  - platform: gpio
    pin: 
      number: D3
    id: pms_set
    name: "Start measuring"
  
interval:
  - interval: 120s
    then:
      - switch.turn_on: pms_set
      - delay: 20s
      - switch.turn_off: pms_set

My questions:

  1. Has the current (ESPHome) code taken into account possibilities to extend the life span of the PMS5003 sensor?
  2. Will a 20 second measurement lead to correct results or is a measurement required over a longer timeframe?
  3. How could this solution best be implemented using the Air Gradient PCB?

Thanks in advance for your support!

4 Likes

Very good idea, i don’t want to replace this thing after 3 years.
You then need one wire more and solder it to an unused GPIO and add some code.

Do you know which pin this is on the connector ?
i don’t have the data-sheet to take a look.

I think this is possible, hope some one will pick this up and add it to the code.
even if you let it run for 45 sec every 2 minutes you expand the lifetime.

Pin 3 of the PMS 5003 should be used.

Hmmm. It can use an I2C mode… I wonder if that would be better than UART

We actually support sleep mode with an undocumented command in the AirGradient Arduino library.

To put into sleep, try:
ag.sleep();

to wake up:
ag.wakeUp();

Hope that helps.

Maybe you can copy that code over to ESP home in case you do not use our Arduino library.

1 Like

That’s very helpful information @Achim_AirGradient. I would also be interested in implementing a sleep/wake up routine for my sensor but I’m using ESPHome instead of the Arduino library. Based on my understanding of your code on GitHub, the PMS also supports the functionality of the SET pin via the I2C bus, right?

Do you maybe have a datasheet that explains how to use SET and maybe also RESET via I2C so that I can contribute towards implementing this in ESPHome? I was looking for a datasheet earlier today but couldn’t find a proper one. It seems like the Chinese version of the Plantower website has much more information than the English version.

Yes datasheets are a bit difficult to get hold off, especially English ones.
I would suggest you check the sleep, wakeup code in our Arduino library and then just copy it over to ESP home.
We do not use the SET pin on our PCB. So besides TX, RC, VCC, G our PCB does not support the other PMS pins. However the sleep and wakeup is purely software driven so it should work.
As far as I know, the PMS5003 does not suppory i2c.

Oops, I just realized that I mixed up I2C and UART here. In any way, I will see if I can extend the ESPHome PMS component to support sleep/wake up too.

I’ve work Jeff Geerling project and rework it for VS Code with PlatformIO.

I took your suggestion and I’m waking up the sensor every 120s for 30s, do the reading and then let’s it go back to sleep.

I’ve been running this for more than 24h and the values I’m getting are pretty good.
I chose 30s because the documentation on @Achim_AirGradient lib was suggesting to wait 30s after waking up the sensor.

1 Like

For anyone using ESPHome, here is the equivalent code that’s working for me that does not require an additional pin:

interval:
  - interval: 150s
    # Two-minute interval to extend the life span of the PMS5003 sensor
    then:
      - switch.turn_on: pms_switch
      - delay: 30s
      - switch.turn_off: pms_switch

# Source: https://github.com/airgradienthq/arduino/blob/master/AirGradient.cpp#L123
switch:
  - platform: template
    name: "PMS5003"
    id: pms_switch
    optimistic: true
    turn_on_action:
      - uart.write:
          id: pms5003_uart
          data: [0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74]
    turn_off_action:
      - uart.write:
          id: pms5003_uart
          data: [0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73]

There is a warning in the log when sleep is called:

[W][pmsx003:108]: PMSX003 length 4 doesn't match. Are you using the correct PMSX003 type?

(maybe that 0x00 at pos 4 should be 0x01 like turn on? not sure)

But it doesn’t seem to affect anything, I can hear the fan cycling on and off and watch the readings stop and go in the logs.

Full example, forked from this one is here

4 Likes

Very elegant solution to use ESPHome UART commands. I thought about adding the functionality to the ESPHome code base but did not get to it so far.

Regarding your question: According to the PMS datasheet at [1], the 0x01 on position four is the actual sleep/wake command and the difference in the last bit is a checksum. My assumption without having looked into the ESPHome code base so far is that currently the PMS component always expects a 32 byte answer because that is the usual communication pattern for measurement data. I’m not sure what the sensor responds after a sleep/wake up but it only seems to be 4 bytes long.

[1] https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf

1 Like

I took a look into the ESPHome code base and confirmed my assumption. Here are the relevant lines of code: esphome/pmsx003.cpp at dev · esphome/esphome · GitHub

I don’t know yet what exactly the sensor sends in these four bytes and if the response differs between sleep and wake up but it should not be hard to create a PR that prevents this constant warning.

1 Like

I ran a small test with the UART debug config this evening.

  - rx_pin: D5
    tx_pin: D6
    baud_rate: 9600
    id: pms5003_uart
    debug:
      after:
        delimiter: "\n"
        bytes: 32

The relevant output lines consistently show this:

[22:13:23][D][uart_debug:114]: >>> 42:4D:E4:00:00:01:73
[22:13:23][W][pmsx003:108]: PMSX003 length 4 doesn't match. Are you using the correct PMSX003 type?
[22:13:23][D][uart_debug:114]: <<< 42:4D:00:04:E4:00:01:77

So the four payload bytes coming back from the sensor are 0x00 0x04 0xE4 0x00. Looking at the PMS datasheet, I’m not sure what this is supposed to mean though.

Update:
I thought about this once more and my best guess is as follows:
0x42 0x4D → standard header
0x00 0x04 → length of following bytes
0xE4 0x00 → repetition of the initial command
0x01 0x77 → checksum bytes

So I guess that the PMS simply confirms any of these “management” commands like sleep/wake or active/passive by replying with the command code.

1 Like

Just wondering, will sleeping/waking the PMS5003 sensor every 30 seconds be integrated into the Airgradient Arduino code?

Thanks!

1 Like

@lbhm - Did you ever get a chance to submit a PR to enhance the PMS5003 ESPHome support with software based sleep? I do not know how to so if you have not, I was going to open an issue in Github adding the information you kindly shared in hopes that someone will submit a PR.

@aruffell I did not follow up on that yet since the workaround by @k-d worked fine for me. I haven’t actively tinkered with my AirGradient in the last months so I’d first have to read up on the topic again.

@lbhm - I hope you do not mind… I created a feature request to enable this in ESPHome. I linked back to this thread.

@aruffell As far as I understand. ESPhome already puts the device to sleep when you have a bigger interval than 0. Mine is set to 3min so it wakes up to do a measurment. Its in the pmsx003 documentation.

I did not see anything about stopping the fan while sleeping in the documentation so I used the Set pin where I had control over the circuit and the sw method on the AirGradient setup. I will test it out to see if mine stops without having to do so specifically. Thanks for letting me know!

Hello,
Building on @rhermsen 's work here PM2.5 value often -1, I have added it to mine with the following code. My recommendation is you save your existing code as a new file, open it, look for the sections below and edit. Note that my settings enable the device for 30 seconds every one minute (3.5 years lifespan seemed short to me but 18 years longer than needed, as estimated in the opening post of this thread).

//following line remarked out to support pm25 sensor sleep
//const int pm25Interval = 5000;
unsigned long previousPm25 = 0;
int pm25 = 0;
//following 3 lines added to support pm25 sensor sleep
const int pm25Interval = 30000;
const int pm25SleepIntvl = 90000;
boolean pm25sleep = false;

//following void added to support pm25 sensor sleep
void sleepPm25()
{
    if (currentMillis - previousPm25 >= pm25SleepIntvl && pm25sleep) {
      ag.wakeUp();
      pm25sleep = false;
    }
}

void updatePm25()
{
//following 2 lines remarked out to support pm25 sensor sleep
//    if (currentMillis - previousPm25 >= pm25Interval) {
//      previousPm25 += pm25Interval;
    if (currentMillis - previousPm25 >= pm25SleepIntvl + pm25Interval) {
      previousPm25 = currentMillis;
      pm25 = ag.getPM2_Raw();
      Serial.println(String(pm25));
//following 2 lines added to support pm25 sensor sleep
      ag.sleep();
      pm25sleep = true;
    }
}