0

I working at air quality station. I measure particulate matter with PMS5003 and meteorological parameters with BME280. Everything seems to work just fine, but sometimes program hangs on checksum calculations.

enter image description here

I wonder if the problem lies either in my software or in hardware. Can anyone have a look at my code and tell me how I can improve it. Thanks in advance :)

Here's my code:

#include <Arduino.h>
#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino

// needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
#include <PubSubClient.h>
#include <Wire.h>
#include <SPI.h>

// BME280 Sensor
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>


//Constants
#define TOKEN "TOKEN"
char thingsboardServer[] = "SERVER_ADDRESS";

// Settings for PMS5003
#define LENG 31  //0x42 + 31 bytes equal to 32 bytes
#define TIMEOUT 10000 //Microseconds to wait for PMS do wakeup

unsigned char buf[LENG];
char ergebnisstr[50];

struct dustvalues {
 unsigned int PM10Val=0; // Byte 4&5
 unsigned int PM2_5Val=0; // Byte 6&7
 unsigned int PM01Val=0; // Byte 8&9
 unsigned int Beyond03=0; // Byte 16&17
 unsigned int Beyond05=0; // Byte 18&19
 unsigned int Beyond1=0; // Byte 20&21
 unsigned int Beyond2_5=0; // Byte 22&23
 unsigned int Beyond5=0; //Byte 24&25
 unsigned int Beyond10=0; //Byte 26&27
};

struct dustvalues dustvalues1, dustvalues2;

//unsigned char gopassive[]={ 0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70 }; //don't need here
//unsigned char readinpassive[]={ 0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71 };
unsigned char gosleep[]={ 0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73 };
unsigned char gowakeup[]={ 0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74 };


// BME280 init
Adafruit_BME280 bme;

// Connection to PubSubClient
WiFiClient espClient;
PubSubClient client(espClient);

int status = WL_IDLE_STATUS;
unsigned long lastSend;

void setup() {
    Serial.begin(9600);
    WiFiManager wifiManager;

    wifiManager.autoConnect("AP", "pass");
    Serial.println("Connected to the network :)");
    delay(500);
    //  pins for RGB diode
    pinMode(12, OUTPUT);
    pinMode(13, OUTPUT);
    pinMode(14, OUTPUT);
    //BME280 sensor check
    if (! bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
    }
    // set server for MQTT PubSubClient Library
    client.setServer( thingsboardServer, 1883 );
    lastSend = 0;

}

void loop() {


    if (!client.connected()) {
    reconnect();
    }
    if ( millis() - lastSend > 30000 ) { // Update and send only after 1 seconds
    getpms5003();
    getAndSendTemperatureAndHumidityData();
    lastSend = millis();
    }
    client.loop();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Connecting to ThingsBoard node ...");
    // Attempt to connect (clientId, username, password)
    if ( client.connect("Stacja3", TOKEN, NULL) ) {
      Serial.println( "[DONE]" );
    } else {
      Serial.print( "[FAILED] [ rc = " );
      Serial.print( client.state() );
      Serial.println( " : retrying in 5 seconds]" );
      // Wait 5 seconds before retrying
      delay( 5000 );
    }
  }
}

void getAndSendTemperatureAndHumidityData()
{
  Serial.println("Collecting temperature data.");

  // Reading temperature or humidity takes about 250 milliseconds!
  float humidity = bme.readHumidity();
  // Read temperature as Celsius (the default)
  float temperature = bme.readTemperature();

  float pressure = bme.readPressure() / 100.0;

  // Check if any reads failed and exit early (to try again).
  if (isnan(humidity) || isnan(temperature) || isnan(pressure)) {
    Serial.println("Failed to read from BME sensor!");
    return;
  }

  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print(" *C ");
  Serial.print("Pressure: ");
  Serial.print(pressure);
  Serial.print("hPa");

  String temperature1 = String(temperature);
  String humidity1 = String(humidity);
  String pressure1 = String(pressure);


  // Just debug messages
  Serial.print( "Sending temperature, humidity & pressure : [" );
  Serial.print( temperature1 ); Serial.print( "," );
  Serial.print( humidity1 ); Serial.print( "," );
  Serial.print( pressure1 );
  Serial.print( "]   -> " );

  // Prepare a JSON payload string
  String payload = "{";
  payload += "\"temperature\":"; payload += temperature1; payload += ",";
  payload += "\"humidity\":"; payload += humidity1;  payload += ",";
  payload += "\"pressure\":"; payload += pressure1;
  payload += "}";

  // Send payload
  char attributes[150];
  payload.toCharArray( attributes, 100 );
  client.publish( "v1/devices/me/telemetry", attributes );
  Serial.println( attributes );
}

bool checkValue(byte *buf, byte leng){
    int receiveSum, checkSum;
    for(byte i = 0; i < (leng - 2); i++){
        receiveSum += int(buf[i]);
    }
    receiveSum += 0x42;
    checkSum = (buf[leng-2] << 8) + buf[leng-1];
    testCheckValue(receiveSum, checkSum);
    if(receiveSum == checkSum){
        return true;
    }
    return false;
}

void testCheckValue(int calc, int found){
    byte strSize = 64;
    char strOut[strSize];
    snprintf(strOut, strSize, "Checksum Calculated: %d\nChecksum Found: %d\n", calc, found);
    Serial.print(strOut);
}


unsigned int transmitPM(char HighB, char LowB, unsigned char *buf){
 unsigned int PMValue;
 PMValue=((buf[HighB]<<8)+buf[LowB]);
 return PMValue;
}


void getpms5003(void){
  unsigned char found=0;

  Serial.println("PMS5003 Wakeup: ");
  Serial.write(gowakeup,7);
  Serial.println();
  Serial.println("gowakeup ist out");
  delay(30000); //Stable data should be got at least 30 Second from wakeup (Datasheet!)
  while (found<2){
   delay(TIMEOUT);
   if(Serial.available()>0){
    if(Serial.find(0x42)){  //start to read when detect 0x42
     Serial.println("0x42 found");
     Serial.readBytes(buf,LENG);
     if (buf[0] == 0x4d){ //second byte should be 0x4D
       found++;
       if(checkValue(buf,LENG)){
        Serial.println("Checksum okay");

        if(found==1){
         dustvalues1.PM01Val=transmitPM(3,4,buf);
         dustvalues1.PM2_5Val=transmitPM(5,6,buf);
         dustvalues1.PM10Val=transmitPM(7,8,buf);

         if (dustvalues1.PM2_5Val <= 36) {
           // digtal write green pin
           digitalWrite(12, LOW);
           // digitalWrite(13, HIGH);
           digitalWrite(14, HIGH);
         }

         if ((dustvalues1.PM2_5Val > 36 ) && (dustvalues1.PM2_5Val <= 80)) {
           // diode change to yellow
           digitalWrite(12, LOW);
           // digitalWrite(13, HIGH);
           digitalWrite(14, LOW);
         }

         if(dustvalues1.PM2_5Val > 84) {
           // diode change to red
           digitalWrite(12, HIGH);
           // digitalWrite(13, HIGH);
           digitalWrite(14, LOW);
         }


         sprintf(ergebnisstr,"PM2.5:%4dug/m3\nPM10: %4dug/m3\n",dustvalues1.PM2_5Val,dustvalues1.PM10Val);
         Serial.println(ergebnisstr);
         Serial.flush();

         // Just debug messages
         Serial.print( "Sending air quality PM2.5 & PM10 values: [" );
         Serial.print( dustvalues1.PM2_5Val ); Serial.print( "," );
         Serial.print( dustvalues1.PM10Val);
         Serial.print( "]   -> " );

         // Prepare a JSON payload string
         String payload = "{";
         payload += "\"pm25\":"; payload += String(dustvalues1.PM2_5Val); payload += ",";
         payload += "\"pm10\":"; payload += String(dustvalues1.PM10Val);
         payload += "}";

         // Send payload
         char attributes[100];
         payload.toCharArray( attributes, 100 );
         client.publish( "v1/devices/me/telemetry", attributes );
         Serial.println( attributes );
       }
        if(found==2){
         dustvalues2.PM01Val=transmitPM(3,4,buf);
         dustvalues2.PM2_5Val=transmitPM(5,6,buf);
         dustvalues2.PM10Val=transmitPM(7,8,buf);
         sprintf(ergebnisstr,"PM1: %4dug/m3\nPM2.5:%4dug/m3\nPM10: %4dug/m3\n",dustvalues2.PM01Val,dustvalues2.PM2_5Val,dustvalues2.PM10Val);
         Serial.println(ergebnisstr);
         Serial.flush();
        }
      }else{
       Serial.println("Checksum not okay");
       Serial.flush();
       if(found>0)found--;
       delay(500);
      }
     }
   }
   }
   }

  found=0;
  Serial.println("PMS5003 - go to sleep");
  Serial.write(gosleep,7);
  Serial.println();
 }

My hardware:

enter image description here

PMS 5003 Datasheet - http://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf

1
  • 1
    Is the checksum function expecting to be run on an 8-bit CPU with only 16-bit integers? You have a 32-bit one there...
    – Majenko
    Dec 9 '17 at 12:09
1

Cited from the documentation

Check code=Start character1+ Start character2+……..+data13 Low 8 bits

Please try to change the code as follows:

...
bool checkValue(byte *buf, byte leng){
    int receiveSum, checkSum;
    receiveSum += 0x42;
    for(byte i = 0; i < (leng - 2); i++){
        receiveSum += int(buf[i]);
        receiveSum = receiveSum & 0xFFFF;
    }

    checkSum = (buf[leng-2] << 8) + buf[leng-1];
    testCheckValue(receiveSum, checkSum);
    if(receiveSum == checkSum){
        return true;
    }
    return false;
}
...

Or use the updated code by the same author :PMS7003-on-Particle

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.