Système de Surveillance Thermique Scolaire : Précis, Temps Réel et Sécurisé
Composants et Fournitures
| Pycom SiPy (Sigfox + MicroPython) | × | 1 |
| Raspberry Pi 3 Modèle B | × | 1 |
| Arduino Nano R3 | × | 1 |
| Convertisseur de Niveau Logique Bidirectionnel (SparkFun) | × | 1 |
| Module RFID RC522 (NFC) | × | 1 |
| Capteur Distance Sharp GP2Y0A41SK0F (4-30 cm, analogique) | × | 1 |
| Capteur Température MLX90614-DCI (I2C) | × | 1 |
| Écran LCD I2C 16×2 (DFRobot) | × | 1 |
| LED + Résistance 330 Ω (×2) | × | 2 |
| Buzzer | × | 1 |
Logiciels et Services
- Arduino IDE
- Visual Studio Code + extension Pymakr (pour SiPy)
- ThingSpeak API (plateforme IoT)
- IFTTT (automatisation email)
- PuTTY, IDLE IDE
À Propos du Projet
Problématique
En Asie, météo chaude + antécédents SRAS 2003 → mesures de température trimestrielles obligatoires en école primaire/secondaire. Problèmes : thermomètres personnels oubliés/cassés/perdus, interdiction de partage (hygiène), coût d'achat. Saisie manuelle fastidieuse pour les enseignants (~40 élèves/classe).
Solution : Système Automatisé
Thème : Impact Social (SqwidNet) / Objectif Développement Durable « Bonne santé et bien-être ».
Mesure automatique de température pour utilisateurs authentifiés (badge RFID), alerte si seuil dépassé.
Architecture : Raspberry Pi + Arduino
- Raspberry Pi : Programme Python + Base MySQL (création auto tables si absent). Attend données via port série.
- Arduino Nano : Lecture badge RFID → envoi ID au Pi → Pi valide utilisateur en BDD → réponse → Arduino affiche « Bienvenue, Prénom » sur LCD.
- Prise température : Capteur distance détecte présence → capteur IR MLX90614 mesure → affichage LCD + envoi Pi (MySQL) + SiPy (Sigfox → ThingSpeak).
- Synchronisation (Handshaking) : Arduino et Pi s'échangent signaux « READY » / « RECEIVED » pour synchroniser les échanges série asynchrones.
Architecture : Sigfox (SiPy)
SiPy reçoit données série de l'Arduino (userID, température partie entière, partie décimale), envoie en bytes (0-255) vers backend Sigfox → rappel ThingSpeak via callback.
Payload personnalisé : userID, temp_entière, temp_décimale. Configuration callback ThingSpeak dans backend Sigfox (Device Type → Device → CALLBACKS).
Cloud : ThingSpeak + IFTTT
- Canal 1 (Privé) : Données brutes Sigfox (température en 2 champs)
- Analyse MATLAB (déclenchée par React sur insertion données) : combine température, transfère vers Canal 2 (Public) avec userID + tableau auto-mis-à-jour
- Si température ≥ 38°C → déclenchement Webhook IFTTT → email d'alerte au personnel
Câblage Arduino Nano (Pinout = Uno)
| Module | Pins |
|---|---|
| RFID RC522 | SDA D10, SCK D13, MOSI D11, MISO D12, IRQ NC, GND, RST D9, 3.3V |
| LCD I2C | SDA A4, SCL A5, GND, 5V |
| Capteur Distance | 5V, GND, Signal A0 |
| Buzzer | GND, Signal D6 |
| Capteur Temp IR | SDA A4, SCL A5, GND, 5V |
| LED | Cathode GND, Anode D7 |
Installation Raspberry Pi
- Flasher Raspbian (balenaEtcher) sur carte SD
- Configuration initiale (HDMI), activer SSH/VNC via
raspi-config - IP statique optionnelle via
/etc/dhcpcd.conf - Installer :
apache2,php,mariadb-server php-mysql - Créer utilisateur root MySQL sécurisé (
DROP USER 'root'@'localhost'; CREATE USER ... GRANT ALL ... FLUSH PRIVILEGES) - Installer phpMyAdmin
Configuration SiPy (Expansion Board 2.0)
- Insérer SiPy sur board (bouton reset vers USB)
- Mise à jour firmware (outil Pycom, choisir région RCZ4 pour Asie)
- Récupérer Device ID et PAC number via code MicroPython
- Enregistrer sur backend Sigfox (choisir pays → entrer ID/PAC → créer compte)
- Test envoi :
s.send(bytes([1..12]))
Configuration Cloud (ThingSpeak + IFTTT)
- IFTTT : Webhooks (Receive web request, event « fever ») → Email (valeurs {{Value1}}, {{Value2}})
- ThingSpeak : 2 canaux (Privé + Public)
- React sur canal privé : condition champ 3 (userID) ≠ 0 → Action MATLAB Analysis
- MATLAB : combine température, écrit sur canal public, si ≥38°C →
webwritevers URL IFTTT
Codes Sources
Arduino Nano (C/C++)
/* 90% codé par Aden (astero.me), 10% libs open-source (RFID, MLX90614) */
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_MLX90614.h>
#define RST_PIN 9
#define SS_PIN 10
#define BUZZER_PIN 7
#define LED_PIN 6
#define DIST_SENSE_PIN A0
MFRC522 mfrc522(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
SoftwareSerial unoSerial(2, 3); // Vers SiPy
boolean tapped = true;
boolean confirmation = false;
String GetUID() {
String uid = "", uid_nospace = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
uid.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
uid.concat(String(mfrc522.uid.uidByte[i], HEX));
}
uid_nospace.concat(uid.charAt(1)); uid_nospace.concat(uid.charAt(2));
uid_nospace.concat(uid.charAt(4)); uid_nospace.concat(uid.charAt(5));
uid_nospace.concat(uid.charAt(7)); uid_nospace.concat(uid.charAt(8));
uid_nospace.concat(uid.charAt(10)); uid_nospace.concat(uid.charAt(11));
return uid_nospace;
}
void setup() {
Serial.begin(9600);
while (!confirmation) { Serial.println("ARDUINO"); confirmation = Serial.readString() == "RAPI"; delay(1000); }
SPI.begin(); mfrc522.PCD_Init(); mlx.begin(); unoSerial.begin(9600);
pinMode(BUZZER_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT);
lcd.init(); lcd.backlight();
}
void loop() {
boolean readySignal = Serial.readString() == "READY";
if (readySignal) { tapped = true; Serial.println("RECEIVED"); }
if (tapped) {
digitalWrite(BUZZER_PIN, 0); digitalWrite(LED_PIN, 0); lcd.clear();
lcd.setCursor(0,0); lcd.print(" Please tap");
lcd.setCursor(0,1); lcd.print(" your card.");
delay(500); tapped = false;
} else {
if (!mfrc522.PICC_IsNewCardPresent()) return;
if (!mfrc522.PICC_ReadCardSerial()) return;
String card_UID = GetUID(); card_UID.toUpperCase();
Serial.print(card_UID); Serial.print("\n");
String rawData = Serial.readString();
int commaPos = rawData.indexOf(',');
String userInitial = rawData.substring(0, commaPos);
int userID = rawData.substring(commaPos + 1).toInt();
lcd.clear();
if (userID != 0 && userInitial != "0") {
lcd.setCursor(0,0); lcd.print("Welcome, ");
lcd.setCursor(0,1); lcd.print(userInitial);
int dist_val = analogRead(DIST_SENSE_PIN);
byte temp_H = 0, temp_L = 0;
float meas_temp = 0.0;
delay(2000);
while ((dist_val < 170) || (dist_val > 200)) {
dist_val = analogRead(DIST_SENSE_PIN);
lcd.setCursor(0,0); lcd.print("Please take");
lcd.setCursor(0,1); lcd.print("your temperature.");
}
digitalWrite(BUZZER_PIN, 1); digitalWrite(LED_PIN, 1); lcd.clear();
meas_temp = (float)mlx.readObjectTempC();
temp_H = floor(meas_temp);
temp_L = (meas_temp - temp_H) * 100;
String sMeasTemp = ""; sMeasTemp += userID; sMeasTemp += ","; sMeasTemp += temp_H; sMeasTemp += ","; sMeasTemp += temp_L;
Serial.println("TEMP"); Serial.println(meas_temp);
if ((meas_temp >= 28) && (meas_temp <= 42)) {
unoSerial.print(sMeasTemp); // Vers SiPy
lcd.setCursor(0,0); lcd.print("Temperature: ");
lcd.setCursor(0,1); lcd.print(" " + String(meas_temp));
}
} else {
lcd.setCursor(0,0); lcd.print("Error!");
lcd.setCursor(0,1); lcd.print("Invalid User.");
}
rawData = Serial.readString();
commaPos = rawData.indexOf(',');
userInitial = rawData.substring(0, commaPos);
if (userInitial == "0") {
lcd.clear(); lcd.setCursor(0,0); lcd.print("Error!");
lcd.setCursor(0,1); lcd.print("Invalid Temperature.");
}
Serial.println("STANDBY"); delay(1000);
mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1();
}
}
Raspberry Pi (Python)
''' Codé par Aden pour Hackster.io Sigfox Competition. astero.me '''
import mysql.connector, serial, os, time
host = "localhost"; user = "root"; password = "password"; databaseName = "smartTemp"
comPort = 'ttyUSB0'; baudRate = 9600
def queryConnection():
cursor = conn.cursor(buffered=True)
cursor.execute("USE `" + databaseName + "`")
return cursor
conn = mysql.connector.connect(host=host, user=user, passwd=password)
ser = serial.Serial('/dev/' + comPort, baudRate, timeout=0)
# Confirmation port série Arduino
connected = False
for x in range(2):
time.sleep(2); ser.write("RAPI")
if not connected:
if ser.readline().strip() == "ARDUINO": comPort = 'ttyUSB0'; connected = True
else: comPort = 'ttyUSB1'; connected = True
ser = serial.Serial('/dev/' + comPort, baudRate)
print("COM PORT confirmed: " + comPort)
countFile = open("count.txt", "a++")
cursor = queryConnection()
# Création BDD + tables
try:
cursor.execute("CREATE DATABASE " + databaseName)
print("Database created.")
except: print("Database exists.")
cursor.execute("CREATE TABLE IF NOT EXISTS `userInfo` (id int, cardID VARCHAR(9), userID VARCHAR(4), userInitial VARCHAR(8))")
cursor.execute("CREATE TABLE IF NOT EXISTS `tempData` (id int, userID VARCHAR(4), dateMeas date, timeMeas time, tempMeasure decimal(5,2))")
count = 1
if os.stat("count.txt").st_size != 0:
for line in countFile: count = int(line)
print("Count restored: " + str(count))
while True:
cursor = queryConnection()
cardID = str(ser.readline().strip())
cursor.execute("SELECT * FROM userInfo WHERE cardID = '" + cardID + "'")
items = cursor.fetchone()
if items:
userID = str(items[2])
userDetails = str(items[3] + ", " + items[2])
currentDate = time.strftime("%Y-%m-%d", time.gmtime())
currentTime = time.strftime("%H:%M:%S", time.gmtime())
ser.write(userDetails.encode())
tempSignal = False
while not tempSignal:
tempSignal = ser.readline().strip() == "TEMP"
tempData = float(ser.readline().strip())
print(tempData)
if 28 <= tempData <= 42:
cursor.execute("INSERT INTO `tempData` VALUES (" + str(count) + ", '" + userID + "', '" + currentDate + "', '" + currentTime + "', '" + str(tempData) + "')")
conn.commit(); count += 1
countFile = open("count.txt", 'w'); countFile.write(str(count))
else:
ser.write(b"0, 0")
else:
ser.write(b", 0"); print("Nothing found")
# Handshake
readySignal = ser.readline().strip() == "STANDBY"
while readySignal:
ser.write(b"READY"); print("sending")
if ser.readline().strip() == "RECEIVED": readySignal = False; print("received")
cursor.close(); conn.close()
SiPy / MicroPython
''' 100% par Reginald '''
from machine import UART
from network import Sigfox
import binascii, socket, time, pycom, sys
pycom.heartbeat(False)
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ4) # RCZ4 = Asie
uart1 = UART(1, baudrate=9600)
uart1.init(9600, bits=8, parity=None, stop=1, pins=('P3', 'P4'), timeout_chars=20)
while True:
try:
recv = uart1.readline()
if recv:
print(binascii.hexlify(sigfox.id()))
print(binascii.hexlify(sigfox.pac()))
sk1 = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
sk1.setblocking(False)
sk1.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False)
dataList = recv.decode("utf-8")
print("dataList: %s" % dataList)
split_val = dataList.split(",")
userID = int(split_val[0])
temp_H = int(split_val[1])
temp_L = int(split_val[2])
print("userID: %d temp_H: %d temp_L: %d" % (userID, temp_H, temp_L))
bData = [userID, temp_H, temp_L]
meas_temp = temp_H + (temp_L * 0.01)
print("measure temperature: %.2f" % meas_temp)
sk1.send(bytes(bData))
sk1.close()
time.sleep(5)
except KeyboardInterrupt:
sys.exit()
ThingSpeak – Script MATLAB
%% Par Aden pour Hackster.io Sigfox Competition. astero.me
readChannelID = 870479;
webhookTrigger = 'https://maker.ifttt.com/trigger/student_fever/with/key/...';
readAPIKey = 'QGHINBPNJQKULBH2';
writeChannelID = 870482;
writeAPIKey = 'R6NJIM8NT5A42R9N';
wholeNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 1);
decimalNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 2) / 100;
userID = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 3);
analyzedData = wholeNumber + decimalNumber;
thingSpeakWrite(writeChannelID, 'Fields', [1,2], 'Values', {analyzedData, userID}, 'WriteKey', writeAPIKey);
if (analyzedData >= 38)
webwrite(webhookTrigger, 'value1', analyzedData, 'value2', userID);
end
Schémas de Câblage







Processus de fabrication
- Surveillance de température professionnelle sur Raspberry Pi avec DS18B20
- Surveillance précise de la température dans un placard serveur avec Raspberry Pi
- Contrôle de température brassage maison DIY : Surveiller et réguler avec Arduino
- Capteur CO2 K30 : Surveillance en temps réel de la qualité de l'air intérieur
- Stores intelligents : contrôle automatisé de la lumière avec Arduino et énergie solaire
- Portique de contrôle de température sans contact pour dépistage rapide et précis
- Arduino UNO & Shield WiFi : Affichage température temps réel sur le Web via série
- Health Band : Bracelet intelligent fiable d'assistance pour personnes âgées
- Agriculture intelligente : Surveillance complète IoT pour l'agriculture du futur