wangyang lin
Published © GPL3+

Wio Terminal Multi-Sensor Environmental Monitoring Station

This project transforms the Seeed Studio Wio Terminal into a multi-sensor environmental monitoring station, leveraging Grove sensor modules

BeginnerProtip2 hours75
Wio Terminal Multi-Sensor Environmental Monitoring Station

Things used in this project

Story

Read more

Code

Wio Terminal Multi-Sensor Environmental Monitoring Station

C/C++
#include <TFT_eSPI.h> // Wio Terminal 
#include "LIS3DHTR.h" // 

#define AIR_QUALITY_PIN A0   // Grove - Air Quality Sensor v1.3  A0/A1
#define MQ2_PIN A2           // Grove - Gas Sensor (MQ2)  A2

TFT_eSPI tft = TFT_eSPI(); // 
LIS3DHTR<TwoWire> lis; // 

// 
int refreshDelay = 2000; // 2000ms
bool fastRefresh = false; // false: , true: 

// 
int currentMode = 0; // 0: , 1: , 2: 

// 
int airQualityThreshold = 500;
int mq2Threshold = 300;

// 
struct Record {
  int airQuality;
  int mq2;
  unsigned long timestamp;
};
#define MAX_RECORDS 10
Record recordArray[MAX_RECORDS]; // 
int recordIndex = 0; // 

// 
int selectedOption = 0; // 0: , 1: MQ2 , 2: 

void setup() {
  // 
  Serial.begin(9600);
  while (!Serial) {
    ; // 
  }

  //  Wio Terminal 
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(2);
  tft.setTextColor(TFT_WHITE);
  tft.setCursor(10, 10);
  tft.println("Starting...");

  // 
  pinMode(AIR_QUALITY_PIN, INPUT);
  pinMode(MQ2_PIN, INPUT); // MQ2 
  pinMode(WIO_LIGHT, INPUT); // 
  pinMode(WIO_MIC, INPUT); // 
  pinMode(WIO_BUZZER, OUTPUT); // 
  digitalWrite(WIO_BUZZER, LOW);
  pinMode(WIO_IR, OUTPUT); // 
  digitalWrite(WIO_IR, LOW);

  // 
  pinMode(WIO_KEY_A, INPUT_PULLUP);
  pinMode(WIO_KEY_B, INPUT_PULLUP);
  pinMode(WIO_KEY_C, INPUT_PULLUP);

  // 
  lis.begin(Wire1);
  if (!lis) {
    tft.fillScreen(TFT_BLACK);
    tft.setCursor(10, 10);
    tft.setTextColor(TFT_RED);
    tft.println("Accelerometer Failed!");
    Serial.println("LIS3DHTR initialization failed!");
    while (1);
  }
  lis.setOutputDataRate(LIS3DHTR_DATARATE_50HZ);
  lis.setFullScaleRange(LIS3DHTR_RANGE_2G);

  // 
  tft.fillScreen(TFT_BLACK);
  tft.setCursor(10, 10);
  tft.setTextColor(TFT_GREEN);
  tft.println("Setup Complete");
  delay(1000);
}

void saveRecord(int airQuality, int mq2) {
  // 
  recordArray[recordIndex].airQuality = airQuality;
  recordArray[recordIndex].mq2 = mq2;
  recordArray[recordIndex].timestamp = millis();

  // 
  recordIndex = (recordIndex + 1) % MAX_RECORDS;
}

void loop() {
  // 
  bool keyAPressed = digitalRead(WIO_KEY_A) == LOW;
  bool keyBPressed = digitalRead(WIO_KEY_B) == LOW;
  bool keyCPressed = digitalRead(WIO_KEY_C) == LOW;

  // 
  if (keyAPressed && currentMode == 0) { //  A 
    currentMode = 1;
    delay(200);
  } else if (keyBPressed && currentMode == 0) { //  B 
    currentMode = 2;
    delay(200);
  } else if (keyCPressed) { //  C 
    if (currentMode == 0) {
      fastRefresh = !fastRefresh; // 
      refreshDelay = fastRefresh ? 1000 : 2000;
    } else {
      currentMode = 0; // 
    }
    delay(200);
  }

  // 
  if (currentMode == 1) {
    if (keyAPressed) { //  A 
      selectedOption = (selectedOption > 0) ? selectedOption - 1 : 2;
      delay(200);
    } else if (keyBPressed) { //  B 
      selectedOption = (selectedOption < 2) ? selectedOption + 1 : 0;
      delay(200);
    }
  }

  // 
  if (currentMode == 1) {
    if (selectedOption == 0) { // 
      if (digitalRead(WIO_KEY_A) == LOW) airQualityThreshold -= 10; //  A 
      if (digitalRead(WIO_KEY_B) == LOW) airQualityThreshold += 10; //  B 
    } else if (selectedOption == 1) { //  MQ2 
      if (digitalRead(WIO_KEY_A) == LOW) mq2Threshold -= 10; //  A 
      if (digitalRead(WIO_KEY_B) == LOW) mq2Threshold += 10; //  B 
    }
  }

  // 
  int airQualityValue = analogRead(AIR_QUALITY_PIN);
  int mq2Value = analogRead(MQ2_PIN); //  analogRead  MQ2 
  float accelX = lis.getAccelerationX();
  float accelY = lis.getAccelerationY();
  float accelZ = lis.getAccelerationZ();
  int builtInLightValue = analogRead(WIO_LIGHT);
  int micValue = analogRead(WIO_MIC);

  // 
  Serial.print("Air Quality: "); Serial.println(airQualityValue);
  Serial.print("MQ2 Gas: "); Serial.println(mq2Value);
  Serial.print("Accel X: "); Serial.println(accelX);
  Serial.print("Accel Y: "); Serial.println(accelY);
  Serial.print("Accel Z: "); Serial.println(accelZ);
  Serial.print("Light: "); Serial.println(builtInLightValue);
  Serial.print("Microphone: "); Serial.println(micValue);

  // 
  if (airQualityValue >= airQualityThreshold || mq2Value >= mq2Threshold) {
    saveRecord(airQualityValue, mq2Value);
  }

  // 
  if (digitalRead(WIO_KEY_A) == LOW && currentMode == 0) {
    if (airQualityValue >= airQualityThreshold || mq2Value >= mq2Threshold) { //  A 
      digitalWrite(WIO_BUZZER, HIGH);
      delay(200);
      digitalWrite(WIO_BUZZER, LOW);
    }
    delay(200); // 
  }
  if (digitalRead(WIO_KEY_B) == LOW && currentMode == 0) {
    digitalWrite(WIO_IR, HIGH); //  B 
    delay(200);
    digitalWrite(WIO_IR, LOW);
    delay(200); // 
  }

  // 
  tft.fillScreen(TFT_BLACK);

  if (currentMode == 0) { // 
    // Air Quality
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 10);
    tft.println("Air Quality");
    tft.setTextColor(TFT_WHITE);
    tft.setCursor(10, 30);
    tft.print("Value: ");
    tft.println(airQualityValue);
    tft.setCursor(160, 30);
    if (airQualityValue < airQualityThreshold) {
      tft.setTextColor(TFT_GREEN);
      tft.println("Good");
    } else {
      tft.setTextColor(TFT_RED);
      tft.println("Poor");
    }

    // Gas Concentration (MQ2)
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 50);
    tft.println("Gas (MQ2)");
    tft.setTextColor(TFT_WHITE);
    tft.setCursor(10, 70);
    tft.print("Value: ");
    tft.println(mq2Value);
    tft.setCursor(160, 70);
    if (mq2Value < mq2Threshold) {
      tft.setTextColor(TFT_GREEN);
      tft.println("Normal");
    } else {
      tft.setTextColor(TFT_RED);
      tft.println("High");
    }

    // Acceleration
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 90);
    tft.println("Acceleration");
    tft.setTextColor(TFT_WHITE);
    tft.setCursor(10, 110);
    tft.print("X: ");
    tft.println(accelX, 2); //  2 
    tft.setCursor(100, 110);
    tft.print("Y: ");
    tft.println(accelY, 2);
    tft.setCursor(190, 110);
    tft.print("Z: ");
    tft.println(accelZ, 2);

    // Built-in Light
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 130);
    tft.println("Built-in Light");
    tft.setTextColor(TFT_WHITE);
    tft.setCursor(10, 150);
    tft.print("Value: ");
    tft.println(builtInLightValue);
    tft.setCursor(160, 150);
    if (builtInLightValue < 400) {
      tft.setTextColor(TFT_YELLOW);
      tft.println("Low");
    } else {
      tft.setTextColor(TFT_GREEN);
      tft.println("Normal");
    }

    // Microphone
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 170);
    tft.println("Microphone");
    tft.setTextColor(TFT_WHITE);
    tft.setCursor(10, 190);
    tft.print("Sound: ");
    tft.println(micValue);
    tft.setCursor(160, 190);
    if (micValue < 200) {
      tft.setTextColor(TFT_GREEN);
      tft.println("Quiet");
    } else {
      tft.setTextColor(TFT_YELLOW);
      tft.println("Noisy");
    }

    // 
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(1);
    tft.setCursor(10, 220);
    tft.print("A: Set | B: Hist | C: ");
    tft.print(fastRefresh ? "Fast" : "Slow");
  } else if (currentMode == 1) { // 
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 10);
    tft.println("Settings");

    // 
    tft.setTextColor(selectedOption == 0 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 30);
    tft.print("Air Quality Th.: ");
    tft.println(airQualityThreshold);

    // MQ2 
    tft.setTextColor(selectedOption == 1 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 50);
    tft.print("MQ2 Threshold: ");
    tft.println(mq2Threshold);

    // 
    tft.setTextColor(selectedOption == 2 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 70);
    tft.println("Back");
  } else if (currentMode == 2) { // 
    tft.setTextColor(TFT_CYAN);
    tft.setCursor(10, 10);
    tft.println("History");

    // 
    int displayIndex = (recordIndex > 0) ? recordIndex - 1 : 0;
    tft.setTextColor(selectedOption == 0 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 30);
    tft.print("Air: ");
    tft.print(recordArray[displayIndex].airQuality);
    tft.setCursor(160, 30);
    tft.print("Gas: ");
    tft.println(recordArray[displayIndex].mq2);

    // 
    tft.setTextColor(selectedOption == 1 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 50);
    tft.print("Time: ");
    tft.println(recordArray[displayIndex].timestamp / 1000);

    // 
    tft.setTextColor(selectedOption == 2 ? TFT_YELLOW : TFT_WHITE);
    tft.setCursor(10, 70);
    tft.println("Back");
  }

  tft.setTextSize(2); // 
  tft.setTextColor(TFT_WHITE);

  delay(refreshDelay); // 
}

Credits

wangyang lin
1 project • 0 followers
Contact

Comments

Please log in or sign up to comment.