/****************************************************************************
** **
** Name: WioTerminal_CO2_traffic_light **
** Author: Achim Kern **
** Interpreter: Arduino IDE 1.8.13 **
** Licence: Freeware **
** Function: measure air quality CO2 and show actual state on TFT **
** **
** Notes: based on idea from SEEED STUDIO and LCARS SmartHome **
** **
** History: **
** **
** 1.00 - 23.10.2020 - initial release **
** - GROVE SCD30 **
** - Buzzer **
** - 3 Buttons **
** - 5 status bmp pictures **
** **
****************************************************************************/
/*
* WIO Terminal TFT Display
*
*/
// TFT library
#include"TFT_eSPI.h"
// TFT display
TFT_eSPI tft;
// Control Pin of LCD
#define LCD_BACKLIGHT (72Ul)
bool tft_backlight = true;
#include "lcd_backlight.hpp"
#include <cstdint>
#include "RTC_SAMD51.h"
#include "DateTime.h"
RTC_SAMD51 rtc;
static LCDBackLight backLight;
/*
* libraries
*
*/
#include <Arduino.h>
// SD card library
#include "Seeed_FS.h"
// image processing library
#include "RawImage.h"
// smooth fonts library
#include "Free_Fonts.h"
/*
* GROVE CO2 & Temperature & Humidity Sensor (SCD30)
* -------------------------------------------------
* The Grove - CO2 & Temperature & Humidity Sensor (SCD30) is a high precision carbon dioxide sensor,
* which is based on Sensirion SCD30. The measuring range of this sensor is 0 ppm-40'000 ppm,
* and the measurement accuracy can reach to (30 ppm + 3%) between 400ppm to 10'000ppm.
* In addition to the Non-Dispersive Infrared(NDIR) measurement technology for CO2 detection,
* the SCD30 integrates Sensirion humidity and temperature sensors on the same sensor module.
*
*/
#include "SCD30.h"
int grove_scd30_co2 = 0;
int grove_scd30_temp = 0;
int grove_scd30_humi = 0;
int scd30_temp_offset = -4;
int scd30_humi_offset = 13;
/*-----------------------------------------*/
/* Function void sensor_co2() */
/* */
/* TASK : read out air sensor data */
/* UPDATE : 23.10.2020 */
/*-----------------------------------------*/
void sensor_co2()
{
// read the sensor
float result[3] = {0};
if (scd30.isAvailable())
{
scd30.getCarbonDioxideConcentration(result);
grove_scd30_co2 = result[0];
grove_scd30_temp = result[1];
grove_scd30_humi = result[2];
// serial print of all sensor values
Serial.print(F("[?] GROVE SCD30 CO2 --> "));
Serial.print("SCD30-CO2:"); Serial.print(grove_scd30_co2);
Serial.print(" SCD30-T:"); Serial.print(grove_scd30_temp+scd30_temp_offset);
Serial.print(" SCD30-H:"); Serial.println(grove_scd30_humi+scd30_humi_offset);
// display co2 pictures on TFT
const char* list[] = {"co2-low-rgb565.bmp", "co2-mid1-rgb565.bmp", "co2-mid2-rgb565.bmp", "co2-high1-rgb565.bmp", "co2-high2-rgb565.bmp"};
// rgb traffic light (planned)
int r,g,b;
uint8_t cnt = 0;
if (grove_scd30_co2<700) { r=0; g=127; b=0; cnt=0; }
if (grove_scd30_co2>=700) { r=0; g=127; b=0; cnt=1; }
if (grove_scd30_co2>=1000) { r=127; g=127; b=0; cnt=2; }
if (grove_scd30_co2>=1300) { r=127; g=0; b=0; cnt=3; }
if (grove_scd30_co2>=1500) { r=127; g=0; b=0; cnt=4; }
drawImage<uint16_t>(list[cnt],0,0);
tft.setTextColor(TFT_BLACK,TFT_WHITE);
tft.setFreeFont(FMB18);
tft.drawNumber(grove_scd30_co2,80,190);
}
}
/*
* Timer
* Generally, you should use "unsigned long" for variables that hold time.
* The value will quickly become too large for an int to store
*/
// this timer is used to update tft display
unsigned long previousMillis = 0;
// send every 10 minutes
// unsigned long interval = 600000;
// send every 3 minutes
// unsigned long interval = 180000;
// send every 30 seconds
unsigned long interval = 10000;
unsigned long counter = 0;
/*-------------------------------------------------------------------------------*/
/* Function void tft_display_status_bar(String room_name, long int room_bg) */
/* */
/* TASK : show tft display status bar */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_status_bar(String room_name, long int room_bg)
{
tft.fillRect(0,0,320,50,room_bg);
tft.setFreeFont(FMB18);
tft.setTextColor(TFT_WHITE);
tft.setCursor((320 - tft.textWidth(room_name)) / 2, 32);
tft.print(room_name);
}
/*-------------------------------------------------------------------------------*/
/* Function void tft_display_room_screen(String room_name, long int room_bg) */
/* */
/* TASK : show tft display room screen */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_room_screen(String room_name, long int room_bg)
{
tft.fillScreen(TFT_WHITE);
tft.fillRect(0,0,320,50,room_bg);
tft.setFreeFont(FMB18);
tft.setTextColor(TFT_WHITE);
tft.setCursor((320 - tft.textWidth(room_name)) / 2, 32);
tft.print(room_name);
// drawing verticle line
tft.drawFastVLine(150,50,190,TFT_DARKGREEN);
// drawing horizontal line
tft.drawFastHLine(0,140,320,TFT_DARKGREEN);
}
/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_temperature(void) */
/* */
/* TASK : show tft display sensor temperature */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_temperature(int temperature)
{
// setting the temperature
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Temperature",15,65);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(temperature,50,95);
//tft.drawNumber(21,50,95);
tft.setFreeFont(FMB12);
tft.drawString("C",100,95);
}
/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_humidity(int humidity) */
/* */
/* TASK : show tft display sensor humidity */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_humidity(int humidity)
{
// setting the humidity
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Humidity",30,160);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(humidity,50,190);
tft.setFreeFont(FMB12);
tft.drawString("%",100,190);
}
void tft_display_time(int timer)
{
DateTime now = DateTime(F(__DATE__), F(__TIME__));
// setting the humidity
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Time",220,65);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB12);
tft.drawNumber(now.hour(),180,95);
tft.setFreeFont(FMB12);
tft.drawString(":",210,95);
tft.setFreeFont(FMB12);
tft.drawNumber(now.minute(),230,95);
}
/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_co2(int co2) */
/* */
/* TASK : show tft display sensor co2 */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_co2(int co2)
{
// setting the CO2
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("CO2",220,160);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(co2,160,190);
tft.setFreeFont(FMB12);
tft.drawString("ppm",250,190);
}
/*-------------------------------------------------------------------------------*/
/* Function void setup() */
/* */
/* TASK : setup all needed requirements */
/* UPDATE : 23.10.2020 */
/*-------------------------------------------------------------------------------*/
void setup()
{
Serial.begin(9600);
delay(3000);
Serial.println(F(" "));
Serial.println(F(" "));
Serial.println(F("Starting..."));
// WIO_TERMINAL
Serial.println(F("WioTerminal CO2 Traffic Light Version 1.00"));
Serial.println(F("GROVE SCD30 connected via I2C"));
Serial.println(F(" "));
Serial.println("initializing backlight...");
backLight.initialize();
static std::uint8_t brightness = 5;
backLight.setBrightness(brightness);
// 3 Wio Terminal buttons
pinMode(WIO_KEY_A, INPUT_PULLUP);
pinMode(WIO_KEY_B, INPUT_PULLUP);
pinMode(WIO_KEY_C, INPUT_PULLUP);
pinMode(WIO_LIGHT, INPUT);
// Initialise SD card
Serial.println(F("[?] SD card initialize.."));
if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI))
{
while (1);
}
// initialize the TFT display
tft.begin();
tft.setRotation(3);
// initialize the scd30 sensor
Serial.println(F("[?] GROVE SCD30 CO2 sensor initialize.."));
Wire.begin();
rtc.begin();
scd30.initialize();
delay(1000);
// read the co2 sensor */
sensor_co2();
DateTime now = DateTime(F(__DATE__), F(__TIME__));
Serial.println("adjust time!");
rtc.adjust(now);
now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
DateTime alarm = DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second() + 15);
rtc.setAlarm(0,alarm); // match after 15 seconds
rtc.enableAlarm(0, rtc.MATCH_HHMMSS); // match Every Day
rtc.attachInterrupt(alarmMatch); // callback whlie alarm is match
}
/*-------------------------------------------------------------------------------*/
/* Function void loop() */
/* */
/* TASK : this runs forever */
/* UPDATE : 23.10.2020 */
/*-------------------------------------------------------------------------------*/
void loop()
{
DateTime now = DateTime(F(__DATE__), F(__TIME__));
// check if some one has pressed a button
if (digitalRead(WIO_KEY_A) == LOW)
{
Serial.println("[x} A Key pressed");
delay(200);
// display room screen
tft_display_room_screen("OFFICE", TFT_BLUE);
// display temperature sensor
tft_display_sensor_temperature(grove_scd30_temp+scd30_temp_offset);
// display humidity sensor
tft_display_sensor_humidity(grove_scd30_humi+scd30_humi_offset);
// display co2 sensor
tft_display_sensor_co2(grove_scd30_co2);
tft_display_time(now.year());
DateTime now = rtc.now();
}
else if (digitalRead(WIO_KEY_B) == LOW)
{
Serial.println("[x] B Key pressed");
delay(200);
// read the co2 sensor */
sensor_co2();
}
else if (digitalRead(WIO_KEY_C) == LOW)
{
delay(100);
if(digitalRead(WIO_KEY_C) == LOW)
{
Serial.println("[x] C Key pressed");
tft_backlight = !tft_backlight;
Serial.println(tft_backlight);
if(tft_backlight==0)
{
backLight.setBrightness(0);
Serial.println("Turning off the LCD backlight");
}
else if(tft_backlight==1)
{
backLight.setBrightness(5);
}
//if (tft_backlight == false) { digitalWrite(LCD_BACKLIGHT, LOW); }
// Turning on the LCD backlight
//if (tft_backlight == true) { digitalWrite(LCD_BACKLIGHT, HIGH); }
delay(200);
}
else
{
};
}
/*
* It is checked whether the time for the transmission interval has already expired
* If the time difference between the last save and the current time is greater
* as the interval, the following function is executed.
*/
if (millis() - previousMillis > interval)
{
// correct timer
previousMillis = millis();
// read the co2 sensor */
sensor_co2();
int light = analogRead(WIO_LIGHT);
Serial.print("Light value: ");
Serial.println(light);
}
}
void alarmMatch(uint32_t flag)
{
Serial.println("Alarm Match!");
DateTime now = rtc.now();
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
}
Comments