Η ιδέα ξεκίνησε από κάτι απλό: πόσο καλός είναι πραγματικά ο αέρας μέσα σε μια σχολική τάξη; Θερμοκρασία, υγρασία, φωτισμός, σκόνη, όλα πράγματα που επηρεάζουν πώς νιώθουν και πώς μαθαίνουν τα παιδιά, αλλά που κανείς συνήθως δεν μετράει.
Η ομάδα έφτιαξε το Class Monitor: έναν μικρό σταθμό με ESP32, που καταγράφει τη θερμοκρασία, την υγρασία, τη φωτεινότητα του χώρου και τα αιωρούμενα σωματίδια, και στέλνει τα δεδομένα σε μια διαδικτυακή βάση (ThingSpeak). Η ιδέα ήταν να μπορεί κάποιος να συγκρίνει τις συνθήκες ανάμεσα σε διαφορετικές αίθουσες, ίσως και σε διαφορετικά σχολεία.
Στήθηκε ένας σταθμός στο εργαστήριο ρομποτικής, ο οποίος κατέγραφε δεδομένα για μερικές ημέρες. Ο αρχικός στόχος ήταν πέντε μονάδες σε δύο σχολεία της Φλώρινας, αλλά το έργο δεν προχώρησε πέρα από αυτό το πρώτο πρωτότυπο.
Παρά ταύτα, το Class Monitor πήρε την 5η θέση στον 8ο Πανελλήνιο Διαγωνισμό Vodafone Generation Next.
Το έργο δεν συνεχίστηκε. Η ιδέα όμως παραμένει καλή, και κάποια στιγμή αξίζει να ξαναδοκιμαστεί, πιθανότατα από άλλη ομάδα και με πιο ολοκληρωμένη εγκατάσταση σε πραγματικές αίθουσες.
Τι έμαθαν τα παιδιά στην πορεία
Η δουλειά πάνω στο Class Monitor δεν ήταν μόνο η κατασκευή του σταθμού. Χρειάστηκε να καταλάβουν πώς λειτουργούν οι αισθητήρες που χρησιμοποίησαν, να μπουν στη λογική του IoT, πώς δηλαδή μια μικρή συσκευή στέλνει δεδομένα σε μια βάση στο διαδίκτυο, και να δουλέψουν με πλατφόρμες όπως το ThingSpeak για να δουν τα αποτελέσματα των μετρήσεών τους. Ασχολήθηκαν επίσης με το ερώτημα γιατί έχει σημασία η ποιότητα του αέρα σε έναν χώρο μάθησης.
Δεδομένα
Η συσκευή δεν καταγράφει πλέον. Μπορείτε να δείτε τα δεδομένα από τη λειτουργία της εδώ: https://thingspeak.mathworks.com/channels/2813296
Λίστα υλικών
Για την υλοποίηση του κάθε σταθμού μέτρησης θα χρειαστούμε τα παρακάτω υλικά:
- ESP32 Development Board – Κόστος 10 ευρώ
- Αισθητήρας θερμοκρασίας – υγρασίας DHT11 – Κόστος 2 ευρώ
- Αισθητήρας σωματιδίων Sharp GP2Y1010AU0F – Κόστος 18 ευρώ
- Αισθητήρας φωτεινότητας I2C – TSL25911 – Κόστος 5 ευρώ
- Τροφοδοτικό USB – Κόστος 10 ευρώ
Εγκατάσταση βιβλιοθηκών


Προγραμματισμός
// Libraries for ESP
#include <WiFi.h>
#include <HTTPClient.h>
// Library for DHT11 sensor
#include <DHT11.h>
// Libraries for Light sensor
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"
//DHT11 object
DHT11 dht11(2);
//Light sensor object
Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
//Constants for Dust Sensor
#define COV_RATIO 0.2
#define NO_DUST_VOLTAGE 400
#define SYS_VOLTAGE 3300
const int iled = 23;
const int vout = 0;
//Wifi settings
const char *ssid = "wifi ssd";
const char *password = "wifi password";
// ThingSpeak settings
const char* server = "http://api.thingspeak.com";
const char* apiKey = "Thing Speak API"; // Replace with your ThingSpeak Write API Key
//Variables for dust sensor
float density, voltage;
int adcvalue;
/**************************************************************************/
/*
Displays some basic information on this sensor from the unified
sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
sensor_t sensor;
tsl.getSensor(&sensor);
Serial.println(F("------------------------------------"));
Serial.print (F("Sensor: ")); Serial.println(sensor.name);
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F(" lux"));
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F(" lux"));
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution, 4); Serial.println(F(" lux"));
Serial.println(F("------------------------------------"));
Serial.println(F(""));
delay(500);
}
/**************************************************************************/
/*
Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
//tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light)
tsl.setGain(TSL2591_GAIN_MED); // 25x gain
//tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain
// Changing the integration time gives you a longer time over which to sense light
// longer timelines are slower, but are good in very low light situtations!
//tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light)
// tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
// tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light)
/* Display the gain and integration time for reference sake */
Serial.println(F("------------------------------------"));
Serial.print (F("Gain: "));
tsl2591Gain_t gain = tsl.getGain();
switch(gain)
{
case TSL2591_GAIN_LOW:
Serial.println(F("1x (Low)"));
break;
case TSL2591_GAIN_MED:
Serial.println(F("25x (Medium)"));
break;
case TSL2591_GAIN_HIGH:
Serial.println(F("428x (High)"));
break;
case TSL2591_GAIN_MAX:
Serial.println(F("9876x (Max)"));
break;
}
Serial.print (F("Timing: "));
Serial.print((tsl.getTiming() + 1) * 100, DEC);
Serial.println(F(" ms"));
Serial.println(F("------------------------------------"));
Serial.println(F(""));
}
/**************************************************************************/
/*
Shows how to perform a basic read on visible, full spectrum or
infrared light (returns raw 16-bit ADC values)
*/
/**************************************************************************/
void simpleRead(void)
{
// Simple data read example. Just read the infrared, fullspecrtrum diode
// or 'visible' (difference between the two) channels.
// This can take 100-600 milliseconds! Uncomment whichever of the following you want to read
uint16_t x = tsl.getLuminosity(TSL2591_VISIBLE);
//uint16_t x = tsl.getLuminosity(TSL2591_FULLSPECTRUM);
//uint16_t x = tsl.getLuminosity(TSL2591_INFRARED);
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
Serial.print(F("Luminosity: "));
Serial.println(x, DEC);
}
/**************************************************************************/
/*
Show how to read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
// That way you can do whatever math and comparisons you want!
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir, full;
ir = lum >> 16;
full = lum & 0xFFFF;
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F(" "));
Serial.print(F("Full: ")); Serial.print(full); Serial.print(F(" "));
Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F(" "));
Serial.print(F("Lux: ")); Serial.println(tsl.calculateLux(full, ir), 6);
}
/**************************************************************************/
/*
Performs a read using the Adafruit Unified Sensor API.
*/
/**************************************************************************/
void unifiedSensorAPIRead(void)
{
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
/* Display the results (light is measured in lux) */
Serial.print(F("[ ")); Serial.print(event.timestamp); Serial.print(F(" ms ] "));
if ((event.light == 0) |
(event.light > 4294966000.0) |
(event.light <-4294966000.0))
{
/* If event.light = 0 lux the sensor is probably saturated */
/* and no reliable data could be generated! */
/* if event.light is +/- 4294967040 there was a float over/underflow */
Serial.println(F("Invalid data (adjust gain or timing)"));
}
else
{
Serial.print(event.light); Serial.println(F(" lux"));
}
}
int Filter(int m)
{
static int flag_first = 0, _buff[10], sum;
const int _buff_max = 10;
int i;
if(flag_first == 0)
{
flag_first = 1;
for(i = 0, sum = 0; i < _buff_max; i++)
{
_buff[i] = m;
sum += _buff[i];
}
return m;
}
else
{
sum -= _buff[0];
for(i = 0; i < (_buff_max - 1); i++)
{
_buff[i] = _buff[i + 1];
}
_buff[9] = m;
sum += _buff[9];
i = sum / 10.0;
return i;
}
}
void sendDataToThingSpeak(float temperature, float humidity, float lux, float dustConcentration) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = String(server) + "/update?api_key=" + apiKey +
"&field1=" + String(temperature) +
"&field2=" + String(humidity) +
"&field3=" + String(lux) +
"&field4=" + String(dustConcentration);
http.begin(url);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
Serial.print("ThingSpeak Response: ");
Serial.println(httpResponseCode);
} else {
Serial.print("Error sending data: ");
Serial.println(http.errorToString(httpResponseCode).c_str());
}
http.end();
} else {
Serial.println("WiFi Disconnected. Unable to send data to ThingSpeak.");
}
}
void setup() {
//Set the mode of the led pin of the dust sensor to output
pinMode(iled, OUTPUT);
digitalWrite(iled, LOW);
//Start serial communication for debugging
Serial.begin(115200);
// First step is to configure WiFi STA and connect in order to get the current time and date.
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
//Start the light sensor
Serial.println(F("Starting Adafruit TSL2591 Test!"));
if (tsl.begin()) {
Serial.println(F("Found a TSL2591 sensor"));
} else {
Serial.println(F("No sensor found ... check your wiring?"));
while (1);
}
// Display some basic information on this sensor
displaySensorDetails();
// Configure the light sensor
configureSensor();
}
void loop() {
//Run every 10 minutes
delay(600000);
// Get light data
uint32_t lum = tsl.getFullLuminosity();
uint16_t ir = lum >> 16;
uint16_t full = lum & 0xFFFF;
float lux = tsl.calculateLux(full, ir);
// Get temperature and humidity
int temperature = 0, humidity = 0;
int result = dht11.readTemperatureHumidity(temperature, humidity);
// Get dust concentration
digitalWrite(iled, HIGH);
delayMicroseconds(280);
adcvalue = analogRead(vout);
digitalWrite(iled, LOW);
adcvalue = Filter(adcvalue);
voltage = (SYS_VOLTAGE / 1024.0) * adcvalue * 11;
if (voltage >= NO_DUST_VOLTAGE) {
voltage -= NO_DUST_VOLTAGE;
density = voltage * COV_RATIO;
} else {
density = 0;
}
// Print data to Serial Monitor
Serial.print("Temperature: "); Serial.print(temperature-2); Serial.print(" °C\t");
Serial.print("Humidity: "); Serial.print(humidity); Serial.print(" %\t");
Serial.print("Lux: "); Serial.print(lux); Serial.print(" lx\t");
Serial.print("Dust: "); Serial.print(density); Serial.println(" µg/m³");
// Send data to ThingSpeak
if (result == 0) {
sendDataToThingSpeak(temperature-2, humidity, lux, density);
} else {
Serial.println("Error reading DHT11 sensor data.");
}
}


Pingback: Επιτυχίες των ομάδων μας στον 8ο Πανελλήνιο Διαγωνισμό Vodafone Generation Next! 🚀 – Μικροί Χάκερ