This project builds a child-in-vehicle alert system that monitors air quality and temperature inside a parked car, sending SMS alerts and making calls to a guardian when dangerous conditions are detected. The system uses an Arduino Uno to read CO2 levels from a CCS811 sensor and temperature/humidity from a DHT11 sensor, then triggers visual and audio alarms (LEDs and a piezo buzzer) while communicating via an LTE modem to notify caregivers of emergencies.
This guide provides a complete parts list, wiring diagram showing connections between the Arduino, sensors, modem, and alert components, step-by-step assembly instructions, and fully commented firmware. Builders will learn how to integrate environmental sensors with cellular communication, implement multi-level alert thresholds based on CO2 concentration, and safely manage power distribution across multiple voltage domains.
Wiring diagram
Gather all the parts
Assemble it in 7 steps
1. Chuẩn bị mô hình thử nghiệm
Dùng nguồn bàn 12V 3A cách ly. Đây là mô hình eCO2, không dùng để bảo vệ trẻ em. CCS811 phải là bo Adafruit 3566 có ổn áp và chuyển mức, không thay bằng bo CCS811 bất kỳ.
- Không nối trực tiếp vào ắc quy hoặc nguồn xe; mạch chưa có bảo vệ xung điện ô tô.
- Không thử nghiệm bằng cách nhốt người hoặc tạo khí nguy hiểm.
2. Chỉnh nguồn trước khi nối thiết bị
Nối adapter qua jack DC (tâm dương) tới VIN+/VIN- của LM2596. Chưa nối tải, dùng đồng hồ chỉnh VOUT đúng 5.0V. Ngắt nguồn rồi mới nối tiếp.
- Điện áp ra sai có thể phá hỏng toàn bộ mạch.
3. Cấp nguồn bo modem
Trên bo Banlinhkien trong ảnh, kiểm tra cầu hàn chọn 5-12V, KHÔNG chọn BAT. VOUT+ cấp VCC modem và đường 5V; VOUT- nối GND chung. Tụ 1000uF đặt sát VCC modem, chân âm về GND. Dùng dây nguồn ngắn và đủ lớn. Gắn anten LTE phù hợp vào đầu nối anten và lắp nano SIM khi tắt nguồn.
- Đảo cực tụ có thể làm tụ nóng hoặc nổ.
- Không cấp modem từ chân 5V Arduino; lấy trực tiếp từ bộ hạ áp.
4. Nối Arduino và đường truyền modem
Nguồn 5V đã chỉnh cấp vào chân 5V Uno, GND nối chung. TXD modem → D8 (Arduino nhận); RXD modem → D9 (Arduino gửi). Dùng tên in trên bo, không đoán theo vị trí hàng chân. Các chân modem khác để trống.
- Khi cắm USB để Deploy, ngắt dây nguồn 5V từ LM2596 tới Uno; giữ GND chung và nguồn riêng cho modem. Không nối đồng thời hai nguồn 5V vào Uno.
5. Nối hai cảm biến
CCS811 VIN → 5V, GND và WAKE → GND, SDA → A4 (dữ liệu), SCL → A5 (xung nhịp). DHT11 VCC → 5V, GND → GND, DATA → D2; điện trở 10k nối DATA lên 5V. Kiểm tra chân theo nhãn của cảm biến, không suy từ màu dây.
- CCS811 cần ổn định ít nhất 20 phút mỗi lần bật, chạy làm quen khoảng 48 giờ lần đầu; eCO2 không phải phép đo CO2 thực.
- DHT11 có sai số lớn; ngưỡng 40 và 42 độ chỉ phục vụ mô phỏng.
6. Nối LED và còi
D4 → điện trở 330Ω → cực A LED1; D5 → điện trở 330Ω → cực A LED2. Hai cực K về GND. Còi piezo chủ động 5V tối đa 20mA: cực + về 5V, cực - tới C transistor 2N3904; E về GND; D6 qua điện trở 1k tới B. Điện trở 100k nối B về GND. Tra đúng B/C/E theo vỏ transistor bạn mua.
7. Kiểm tra trước khi vận hành
Kiểm tra nguồn 5V không sụt khi modem phát. SIM phải có SMS, thoại, tài khoản và VoLTE được nhà mạng hỗ trợ trên A7680C. Chỉ thử với số người giám hộ đồng ý nhận tin; không dùng số khẩn cấp.
- Hai LED luân phiên và còi ngắn mỗi 5 giây báo lỗi cảm biến, không có nghĩa môi trường an toàn.
- Cuộc gọi bị ngắt 20 giây tính từ lệnh quay số, không đảm bảo điện thoại đổ chuông đủ 20 giây. Không có microphone/loa thoại trong mạch này.
Review all connections
1. Connections between "supply" and "Arduino"
2. Connections between "jack" and "Arduino"
3. Connections between "buck" and "Arduino"
4. Connections between "modem" and "Arduino"
5. Connections between "cap" and "Arduino"
6. Connections between "gas" and "Arduino"
7. Connections between "dht" and "Arduino"
8. Connections between "pull" and "Arduino"
9. Connections between "led1" and "Arduino"
10. Connections between "r1" and "Arduino"
11. Connections between "led2" and "Arduino"
12. Connections between "r2" and "Arduino"
13. Connections between "buzzer" and "Arduino"
14. Connections between "q" and "Arduino"
15. Connections between "rb" and "Arduino"
16. Connections between "pd" and "Arduino"
Deploy the firmware
// Wiring verified: modem software UART RX8 TX9; DHT D2; LED D4/D5; buzzer D6; I2C A4/A5.
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_CCS811.h>
#include <DHT.h>
#include <AltSoftSerial.h>
// Dien so nguoi giam ho theo dang +84...; de trong se KHONG goi/gui SMS.
const char PHONE[] = "+84396869634";
const uint16_t LEVEL1_PPM=1000, LEVEL2_PPM=2000, LEVEL3_PPM=5000;
const uint8_t LED1=4, LED2=5, BUZZ=6;
DHT dht(2,DHT11);
Adafruit_CCS811 gas;
AltSoftSerial modem; // Uno RX D8, TX D9
uint16_t eco2=0;
float temp=NAN;
bool gasOK=false, gasValid=false, tempValid=false;
uint32_t lastRead=0, lastGas=0, lastTemp=0, nextInit=15000;
uint32_t lastSMS=0,lastCall=0, started=0;
bool smsEver=false,callEver=false;
uint8_t level=0,initStep=0;
// Modem state: 0 init, 1 idle, 2 SMS prompt, 3 SMS result, 4 calling, 5 hangup
uint8_t state=0;
char response[140]; uint8_t used=0;
bool gotOK=false,gotError=false,prompt=false,sent=false;
void clearReply(){used=0;response[0]=0;gotOK=gotError=prompt=sent=false;}
void command(const __FlashStringHelper* s){clearReply();modem.println(s);started=millis();}
bool due(uint32_t now,uint32_t then,uint32_t interval){return (uint32_t)(now-then)>=interval;}
void receive(){
while(modem.available()){
char c=modem.read(); if(c=='>')prompt=true;
if(c=='\n'){
response[used]=0;
if(strstr(response,"OK"))gotOK=true;
if(strstr(response,"ERROR"))gotError=true;
if(strstr(response,"+CMGS:"))sent=true;
used=0;
} else if(c!='\r' && used<sizeof(response)-1)response[used++]=c;
}
}
void sample(uint32_t now){
// DHT library takes a short synchronous reading; no delay-based alarm timing.
if(!due(now,lastRead,2000))return;
lastRead=now;
float t=dht.readTemperature(), h=dht.readHumidity();
if(!isnan(t)){temp=t;lastTemp=now;tempValid=true;}
if(gasOK && gas.available() && gas.readData()==0){eco2=gas.geteCO2();lastGas=now;gasValid=true;}
if(gasOK && !isnan(t) && !isnan(h))gas.setEnvironmentalData(h,t);
Serial.print(F("eCO2="));Serial.print(eco2);Serial.print(F(" T="));Serial.println(temp);
}
void alarms(uint32_t now){
bool gv=gasValid&&!due(now,lastGas,10000),tv=tempValid&&!due(now,lastTemp,10000);
level=0;
if(gv&&eco2>=LEVEL1_PPM)level=1;
if((gv&&eco2>=LEVEL2_PPM)||(tv&&temp>40))level=2;
if((gv&&eco2>=LEVEL3_PPM)||(tv&&temp>=42))level=3;
bool fault=now>30000&&(!gv||!tv);
digitalWrite(LED1,level>=1 || (fault&&now%1000<500));
digitalWrite(LED2,level>=2 || (fault&&now%1000>=500));
bool sound=level==3 || (level==2&&now%300<150) || (level==1&&now%1000<200);
if(fault && !level)sound=now%5000<100;
digitalWrite(BUZZ,sound);
}
void startCall(uint32_t now){
clearReply(); modem.print(F("ATD"));modem.print(PHONE);modem.println(';');
lastCall=now;callEver=true;started=now;state=4;
}
void network(uint32_t now){
receive();
if(state==0){
if((int32_t)(now-nextInit)<0)return;
if(initStep==0){modem.end();modem.begin(115200);command(F("AT"));initStep=1;return;}
if(initStep==2){modem.end();modem.begin(9600);command(F("ATE0"));initStep=3;return;}
if(gotError||due(now,started,3000)){initStep=0;nextInit=now+3000;return;}
if(!gotOK)return;
switch(initStep){
case 1:command(F("AT+IPR=9600"));initStep=2;nextInit=now+300;return;
case 2:modem.end();modem.begin(9600);command(F("ATE0"));initStep=3;return;
case 3:command(F("AT+CMGF=1"));initStep=4;return;
default:state=1;Serial.println(F("Modem ready"));return;
}
}
if(state==4){if(due(now,started,20000)){command(F("ATH"));state=5;}return;}
if(state==5){if(gotOK||gotError||due(now,started,3000))state=1;return;}
if(state==2){
if(prompt){
clearReply();modem.print(F("MO HINH eCO2 - MUC "));modem.print(level);
modem.print(F(" eCO2="));modem.print(eco2);modem.print(F("ppm T="));
if(tempValid)modem.print(temp,1);else modem.print(F("LOI"));
modem.print(F("C. KIEM TRA NGAY!"));modem.write(26);started=now;state=3;
}else if(gotError||due(now,started,5000)) {modem.write(27);state=1;}
return;
}
if(state==3){
if(gotOK||gotError||due(now,started,30000)){
Serial.println(sent?F("SMS accepted"):F("SMS failed/unknown"));state=1;
}return;
}
if(!PHONE[0] || !level)return;
// At level 3, place call first so a slow SMS cannot postpone the SOS call.
if(level==3&&(!callEver||due(now,lastCall,60000))){startCall(now);return;}
if(!smsEver||due(now,lastSMS,60000)){
lastSMS=now;smsEver=true;clearReply();
modem.print(F("AT+CMGS=\""));modem.print(PHONE);modem.println('"');started=now;state=2;
}
}
void setup(){
pinMode(LED1,OUTPUT);pinMode(LED2,OUTPUT);pinMode(BUZZ,OUTPUT);
Serial.begin(9600);Wire.begin();Wire.setWireTimeout(25000,true);dht.begin();
gasOK=gas.begin(0x5A);modem.begin(115200);
Serial.println(F("DEMO ONLY: eCO2 is NOT measured CO2. Set PHONE in source."));
}
void loop(){uint32_t now=millis();network(now);sample(now);alarms(now);}Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace, diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




