Search code examples
c++arduinohexdecodesensors

Decoding Help, I've bought this 7in1 Air Quality M701 sensor from china and the output is all in hex and the documentation is hard to read


The Sensor is called 7-in-1 air quality detection module M701

I attached the sensor to my Arduino mega RX pin to read the data from it and this is the output,

3C  02  01  BD  00  0C  00  61  00  0E  00  11  81  01  67  09  7A
3C  02  01  B3  00  0C  00  6F  00  0E  00  11  81  01  67  09  7E
3C  02  01  AE  00  0C  00  6E  00  0E  00  11  81  01  67  09  78
3C  02  01  AE  00  0C  00  6E  00  0E  00  11  81  01  67  09  78
3C  02  01  AE  00  0C  00  6D  00  0E  00  11  81  01  67  09  77

I found 3C to be a repeating starting character every second so I've taken it as an indicator for a new line. it outputs every 1 second.

here is the documentation they sent https://drive.google.com/file/d/1JCaxHthLvWbChXGb8kIOsRB3LvKvwAf8/view?usp=sharing

here is my Arduino code for reading the sensor

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void p(byte X) {
  if (X == 0x3C) {
    Serial.println();
  }

  if (X < 16) {
    Serial.print("0");
  }

  Serial.print(X, HEX);
  Serial.print("\t");
}
void loop() {
  if (Serial1.available()) {     // If anything comes in Serial1 (pins 0 & 1)
    //    Serial.print("0x");
    //    Serial.println();   // read it and send it out Serial (USB)
    p(byte (Serial1.read()));
  }
}

here is the raw output if I simply just print without newlines or spaces

3C21BC0C08D0E011811679A53C21BD0C08E0E011811679A73C21BD0C08E0E011811679A73C21BD0C08E0E011811679A73C21BD0C08E0E011811679A7

this is 4 seconds of execution

6021185012010501401712911039126602118601209901401712911039121602118601209601401712911039118602118601209501401712911039117

or this without the (HEX) argument in Serial.println.

Could anyone help me decode this? Im pretty new to decoding and hex stuff, so I'm clueless on how to read data from it.


Solution

  • well I figured it out, so the documentation was google translate, so it didn't help when the tables were distorted, I've used the Chinese version to figure out the data designation(dunno the lingo) so here goes

    3C  02  01  BD  00  0C  00  61  00  0E  00  11  81  01  67  09  7A
    3C =  Adress
    02 =  Function 
    01 BD = CO2
    00 0C = formaldehyde
    00 61 = TVOC
    00 0E = PM2.5
    00 11 = PM10
    81 01 = temperature 
    67 09 = humidity
    7A = CRC
    

    Edit:

    Finally got it to work properly! (except for the negative temperature values, partly solved but hex values keeps adding a zero before the low hex causing the result to be wrong)

    first, Here is my wiring setup:

    enter image description here

    Here is my code:

    void setup() {
    Serial.begin(9600);
      Serial1.begin(9600);
    }
    // int i = 0;
    int C02H;
    int C02L;
    
    int formaldehydeH;
    int formaldehydeL;
    
    int TVOCH;
    int TVOCL;
    
    int PM25H;
    int PM25L;
    
    int PM10H;
    int PM10L;
    
    int TempH;
    int TempL;
    
    int HumdH;
    int HumdL;
    int myval;
    
    float combineTwoHexIntoOneFloat(byte value1,byte value2){
        String string1 = String(value1, HEX);
        String string2 = String(value2, HEX);
        String string3;
        string3 = string1 + string2;
        float y;
        char *endptr;
        y = strtol(string3.c_str(), &endptr, 16);
        // Serial.println(x / 10, 2);
      return  y;
    }
    int combineTwoHexIntoOneInt(byte value1,byte value2){
        String string1 = String(value1, HEX);
        String string2 = String(value2, HEX);
        String string3;
        string3 = string1 + string2;
        int y;
        char *endptr;
        y = strtol(string3.c_str(), &endptr, 16);
        // Serial.println(x / 10, 2);
      return y;
    }
    void parseDataStream(byte X, int i) {
      if (i == 2) {
        C02H = X;
      }
      if (i == 3) {
        C02L = X;
        // Serial.print("C02 HEX Value:  ");
        // Serial.print(C02H, HEX);
        // Serial.print(" ");
        // Serial.println(C02L, HEX);
        Serial.print("C02 Decimal Value:  ");
        Serial.println(combineTwoHexIntoOneInt(C02H,C02L));
      }
      if (i == 4) {
        formaldehydeH = X;
      }
      if (i == 5) {
        formaldehydeL = X;
        // Serial.print("FormaldehydeH HEX Value:  ");
        // Serial.print(formaldehydeH, HEX);
        // Serial.print(" ");
        // Serial.println(formaldehydeL, HEX);
        Serial.print("Formaldehyde Decimal Value:  ");
        // Serial.println(formaldehydeH * 256 + formaldehydeL);
        Serial.println(combineTwoHexIntoOneInt(formaldehydeH,formaldehydeL));
    
        
      }
      if (i == 6) {
        TVOCH = X;
      }
      if (i == 7) {
        TVOCL = X;
        // Serial.print("TVOC HEX Value:  ");
        // Serial.print(TVOCH, HEX);
        // Serial.print(" ");
        // Serial.println(TVOCL, HEX);
        Serial.print("TVOC Decimal Value:  ");
        // Serial.println(TVOCH * 256 + TVOCL);
        Serial.println(combineTwoHexIntoOneInt(TVOCH,TVOCL));
    
      }
      if (i == 8) {
        PM25H = X;
      }
      if (i == 9) {
        PM25L = X;
        // Serial.print("PM2.5 HEX Value:  ");
        // Serial.print(PM25H, HEX);
        // Serial.print(" ");
        // Serial.println(PM25L, HEX);
        Serial.print("PM2.5 Decimal Value:  ");
        // Serial.println(PM25H * 256 + PM25L);
        Serial.println(combineTwoHexIntoOneInt(PM25H,PM25L));
    
      }
      if (i == 10) {
        PM10H = X;
      }
      if (i == 11) {
        PM10L = X;
        // Serial.print("PM10 HEX Value:  ");
        // Serial.print(PM10H, HEX);
        // Serial.print(" ");
        // Serial.println(PM10L, HEX);
        Serial.print("PM10 Decimal Value:  ");
        // Serial.println(PM10H * 256 + PM10L);
        Serial.println(combineTwoHexIntoOneInt(PM10H,PM10L));
    
      }
    
      if (i == 12) {
        TempH = X;
      }
      if (i == 13) {
        TempL = X;
        // Serial.print("Temperature HEX Value:  ");
        // Serial.print(TempH, HEX);
        // Serial.print(" ");
        // Serial.println(TempL, HEX);
        Serial.print("Temperature Decimal Value:  ");
        // Serial.println((TempH * 256 + TempL));
        Serial.println(combineTwoHexIntoOneFloat(TempH,TempL)/10,2);
        
        //For Negative Values, a bit buggy tho
        // Serial.println((TempH << 8) | TempL);
    
    
      }
    
      if (i == 14) {
        HumdH = X;
      }
      if (i == 15) {
        HumdL = X;
        // Serial.print("Humidity HEX Value:  ");
        // Serial.print(HumdH, HEX);
        // Serial.print(" ");
        // Serial.println(HumdL, HEX);
        Serial.print("Humidity Decimal Value:  ");
        // Serial.println((HumdH+ HumdL));
        Serial.println(combineTwoHexIntoOneFloat(HumdH,HumdL)/10,2);
    
      }
    }
    
    void loop() {
    
      for (int k = 0; k < 17; k++) {
        while (!Serial1.available())
          ;  // wait for a character
        int incomingByte = Serial1.read();
        // Serial.print(incomingByte,HEX);
        // Serial.print(' ');
        parseDataStream(incomingByte, k);
      }
      Serial.println();
    }
    

    it ain't the best solution but it is a working one. here is an example output

    C02 Decimal Value:  415
    Formaldehyde Decimal Value:  12
    TVOC Decimal Value:  30
    PM2.5 Decimal Value:  15
    PM10 Decimal Value:  18
    Temperature Decimal Value:  37.70
    Humidity Decimal Value:  72.90
    

    Ignore my temperature and humidity values, my tweezers chose to show up outta nowhere and sit on it, causing the sensor to die. literally minutes before finishing the code :(