Challenger - ZMOD4510 - Outdoor Air Quality Sensor
Hello element14 Family,
Please find the code for the device constructed as a part of the Summer of Sensors Design Challenge.
Since the Renesas code was proprietary and was downloaded through a request on their portal, the license agreements will not allow me post it publicly on the forum.
However, I have indicated the sections where the downloaded library code can be directly included for reconstructing the results of this exercise.
Hardware:
- Renesas ZMOD4510 EVK Outdoor Air Quality Sensor
- Adafruit Feather M0 WiFi - ATSAMD21 + ATWINC1500
- Adafruit FeatherWing OLED - 128x32 OLED Add-on For Feather
- Adafruit Si7021 Temperature & Humidity Sensor Breakout Board
- Adafruit Electret Microphone Amplifier - MAX4466 with Adjustable Gain
Software:
- Arduino IDE
- ZMOD4510 - OAQ 2nd Gen Firmware - Selective Ozone and Ultra-Low Power (request for secure access)
- Library: Arduino SAMD Boards
- Library: Adafruit SAMD Boards
- Library: Adafruit SSD1306 (and associated dependencies)
- Library: Adafruit Si7021 Library
- Library: Blynk
Arduino Code:
/* Peronalized Air Quality & Sound Measurement Device * This file is part of the element14 Summer of Sensors Challenge * Category : In The Air Tonight * Hardware : Renesas ZMOD4510 Outdoor Air Quality Sensor * Due Date : 17th of November, 2022 * Authors : Renesas Electronics Corporation, Ladyada, Abhay Joshi * Usage : Search For Fields Labelled {USER INPUT:} & Input Relevant Data * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* USER INPUT: Template ID, Device Name, Auth Token Provided By Blynk.Cloud */ #define BLYNK_TEMPLATE_ID "" #define BLYNK_DEVICE_NAME "" #define BLYNK_AUTH_TOKEN "" /* Comment This To Save Space */ #define BLYNK_PRINT Serial /*******************************************************************/ /* INCLUDES */ /*******************************************************************/ /* Includes For Adafruit OLED Featherwing */ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> /* Includes For Si7021 Temperature & Humidity Sensor */ #include "Adafruit_Si7021.h" /* USER INPUT: Includes For ZMOD4510 Gas Sensor */ /* Includes For Blynk IoT Cloud Reporting */ #include <WiFi101.h> #include <BlynkSimpleWiFiShield101.h> /*******************************************************************/ /* MACROS */ /*******************************************************************/ /* OLED Display Width (Pixels) */ #define SCREEN_WIDTH 128 /* OLED Display Heighth (Pixels) */ #define SCREEN_HEIGHT 32 /* OLED Reset Pin (-1 If Sharing Arduino Reset Pin) */ #define OLED_RESET -1 /* OLED I2C Address (Datasheet: 0x3C for 128x32) */ #define SCREEN_ADDRESS 0x3C /* Read Battery Level */ /* Ref: https://learn.adafruit.com/adafruit-feather-m0-adalogger/power-management */ #define VBATPIN A7 /* Read Microphone Level */ /* Ref: https://learn.adafruit.com/adafruit-microphone-amplifier-breakout/measuring-sound-levels */ #define MICROPHONE_PIN A5 /*******************************************************************/ /* HANDLERS */ /*******************************************************************/ /* OLED Display */ Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void error_handle(); /* Temperature & Humidity Sensor */ Adafruit_Si7021 sensor = Adafruit_Si7021(); /*******************************************************************/ /* GLOBAL VARIABLES */ /*******************************************************************/ /* USER INPUT: Variables Specific To ZMOD4510 Gas Sensor*/ /* Variables Specific To Environmental Sensor */ bool enableHeater = false; /* Variables Specific To Electret Microphone */ const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz) unsigned int sample; /* Blynk.Cloud Authorization Token */ char auth[] = BLYNK_AUTH_TOKEN; /* USER INPUT: WiFi Credentials */ char ssid[] = ""; char pass[] = ""; /*******************************************************************/ /* FUNCTIONS */ /*******************************************************************/ /*******************************************************************/ /* SETUP */ /*******************************************************************/ void setup() { /* Initialize The Serial Port */ Serial.begin(115200); /* Setup WiFi & Blynk.Cloud Interface */ /* Ref: https://github.com/blynkkk/blynk-library/blob/master/examples/Boards_WiFi/Adafruit_Feather_M0_WiFi/Adafruit_Feather_M0_WiFi.ino */ WiFi.setPins(8, 7, 4, 2); Blynk.begin(auth, ssid, pass); /* Delay For System Stability */ delay(2000); /* Initialize The Temperature & Humidity Sensor */ if (!sensor.begin()) { Serial.println("Si7021 Sensor Error!"); for(;;); // Don't Proceed, Loop Forever } /* Initialize The OLED Display */ /* SSD1306_SWITCHCAPVCC - Generate Display Voltage From 3.3V Internally */ if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 OLED Display Error")); for(;;); // Don't Proceed, Loop Forever } display.clearDisplay(); display.setTextSize(1); // Normal 1:1 Pixel Scale display.setTextColor(SSD1306_WHITE); // Draw White Text display.setCursor(0, 0); // Start At Top-left Corner display.cp437(true); // Use Full 256 Char 'Code Page 437' Font /* Print A Welcome Message */ display.println(F("Welcome To")); display.println(F("element14")); display.println(F("Summer of Sensors")); display.println(F("Design Challenge!\n")); display.display(); delay(5000); display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 10); display.println(F("In The Air Tonight...")); display.display(); delay(100); /* Additional Delay For System Stability */ delay(2000); Serial.println(F("Starting The ZMOD4510 Gas Sensor!")); /* USER INPUT: Enter The Setup Section Code Obtained From The Renesas Library */ } /*******************************************************************/ /* LOOP */ /*******************************************************************/ void loop() { Blynk.run(); /* USER INPUT: Enter The Loop Section Code Obtained From The Renesas Library Download */ /* Use sensor.readHumidity() & sensor.readTemperature() for algo_input */ /* Report Battery Level */ float measuredvbat = analogRead(VBATPIN); measuredvbat *= 2; // we divided by 2, so multiply back measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage measuredvbat /= 1024; // convert to voltage Serial.print(F("VBat = ")); Serial.print(measuredvbat); unsigned long startMillis = millis(); // Start of sample window unsigned int peakToPeak = 0; // peak-to-peak level unsigned int signalMax = 0; unsigned int signalMin = 1024; /* Collect Data For 50 Milliseconds */ while (millis() - startMillis < sampleWindow) { sample = analogRead(MICROPHONE_PIN); if (sample < 1024) { if (sample > signalMax) { signalMax = sample; // save just the max levels } else if (sample < signalMin) { signalMin = sample; // save just the min levels } } } /* Ref: https://forums.adafruit.com/viewtopic.php?f=8&t=100462&p=503661 */ peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude double volts = ((peakToPeak * 3.3) / 1024) * 0.707; // convert to RMS voltage double first = log10(volts/0.00631)*20; double decibels = first + 94 - 44 - 25; display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setCursor(0, 0); display.println(F("In The Air Tonight")); /* Display & Report Temperature */ display.print(F("T:")); display.print(sensor.readTemperature(), 2); Blynk.virtualWrite(V5, sensor.readTemperature()); display.print(F("C ")); /* Display & Report Relative Humidity */ display.print(F("RH:")); display.print(sensor.readHumidity(), 2); Blynk.virtualWrite(V6, sensor.readHumidity()); display.print(F("% ")); /* Display & Report AQI */ display.print(F(" AQI:")); if (lib_ret == OAQ_2ND_GEN_STABILIZATION) { display.print(F("Warming Up... ")); /* Convey That The Sensor Is In Warm Up State */ Blynk.virtualWrite(V7, -1); } else { display.print(algo_results.EPA_AQI); Blynk.virtualWrite(V7, algo_results.EPA_AQI); } display.println(); /* Display & Report Noise Level (dB) */ display.print(F("Noise:")); display.print(decibels); Blynk.virtualWrite(V8, decibels); display.print(F("dB ")); /* Call The Drawing Function */ display.display(); delay(100); /* Issue A Low Battery Warning (400 mAh LiPo) */ if(measuredvbat < 3.7) { display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setCursor(10, 10); display.println(F("CHARGE BATTERY NOW!")); display.display(); /* Hold The Message On The Display For Some Time */ delay(2000); } } void error_handle() { /* Implement Specific Error Handling Routines */ while(1); }