Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.

PMS5003 Sleep Mode
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

PMS5003 Sleep Mode

by SeBassTian on Sat Jul 18, 2020 6:36 pm


I'm building a weather station using the PMS5003 amongst other sensors. The PMS5003 is connected to a Huzzah32 Feather using hardware serial. As far as my understanding goes, the PMS5003 has a sleep mode, that can be triggered, sending a command or using the set/reset pins. I tried both options to the same result and I think I would prefer the software solution, since using the set/reset pins causes the sensor to start up when the ESP32 goes to deep sleep, whereas when using the software commands, it stays in sleep until the ESP32 wakes up and then wakes up the sensor.

Here is problem that I encounter:

Using the sample code from Adafruit website and from some this GitHub Repo, I used this test sketch to work on the sleep mode.

Code: Select all | TOGGLE FULL SIZE
#define pmsSerial Serial1

void setup() {
  // Wait for serial monitor to open
  while (!Serial) delay(10);

  // Wait one second for sensor to boot up!

struct pms5003data {
  uint16_t framelen;
  uint16_t pm10_standard, pm25_standard, pm100_standard;
  uint16_t pm10_env, pm25_env, pm100_env;
  uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
  uint16_t unused;
  uint16_t checksum;

struct pms5003data data;

void loop() {

  // Wake up the Air Quality Sensor
  Serial.println("Wake Up Sensor");
  uint8_t cmdWakeUp[] = { 0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74 };
  pmsSerial.write(cmdWakeUp, sizeof(cmdWakeUp));

  Serial.println("Turn On Active Mode");
  uint8_t cmdActiveMode[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 };
  pmsSerial.write(cmdActiveMode, sizeof(cmdActiveMode));
   // Wait for the sensor to get stable readings

  Serial.println("Start Reading");
  uint32_t start = millis();
    // reading data was successful!
    if ( readPMSdata(&pmsSerial) ) break;
  } while (millis() - start < 3500);

  Serial.println("Concentration Units (standard)");
  Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
  Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
  Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
  Serial.println("Concentration Units (environmental)");
  Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
  Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
  Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
  Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
  Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
  Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
  Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
  Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
  Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);

  // Send PMS5003 to sleep
  Serial.println("Put Sensor To Sleep");
  uint8_t commandSleep[] = { 0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73 };
  pmsSerial.write(commandSleep, sizeof(commandSleep));

/* PMS5003 Read data from stream */
boolean readPMSdata(Stream *s) {

  uint8_t buffer[32];   
  uint16_t sum = 0;

  if (! s->available()) {
    Serial.println("Not available");
    return false;
  // Read a byte at a time until we get to the special '0x42' start-byte
  if (s->peek() != 0x42) {
    return false;

  // Now read all 32 bytes
  if (s->available() < 32) {
    return false;
  s->readBytes(buffer, 32);

  // Check that start byte is correct!
  if (buffer[0] != 0x42) {
    Serial.println("Start byte wrong.");
    return false;

  // get checksum ready
  for (uint8_t i=0; i<30; i++) {
    sum += buffer[i];

  /* debugging
  for (uint8_t i=2; i<32; i++) {
    Serial.print("0x"); Serial.println(buffer[i], HEX);

  // The data comes in endian'd, this solves it so it works on all platforms
  uint16_t buffer_u16[15];
  for (uint8_t i=0; i<15; i++) {
    buffer_u16[i] = buffer[2 + i*2 + 1];
    buffer_u16[i] += (buffer[2 + i*2] << 8);

  // put it into a nice struct :)
  memcpy((void *)&data, (void *)buffer_u16, 30);

  if (sum != data.checksum) {
    Serial.println("Checksum failure");
    return false;

  Serial.print("Checksum = ");
  Serial.println( data.checksum );

  // success!
  return true;

I know the sleep mode is working, since the fan stops and there is no data coming from the sensor's TX pin when monitoring it on an oscilloscope. When waking the sensor up, the fan starts and the sensor is sending data again.

Problem is, that if I send the sensor to sleep and wake it up again, it is not sending the data properly, missing the particle counts (particles_03um, particles_05um, particles_10um, particles_25um, particles_50um are always 0). Also I'm not 100% confident about the other values.

Testing further, it seems the wakeup command is causing the issue. Calling only the active mode command at the beginning of the loop is not causing the data loss. Calling the wakeup and then active mode with and without the sensor being in sleep mode prior is causing the data loss.

Has anybody encountered this issue before? Am I missing something when waking up the sensor or using the serial connection?

Any help is appreciated!

Posts: 1
Joined: Sat Jul 18, 2020 5:47 pm

Please be positive and constructive with your questions and comments.