Đi học thoai - Một dự án thú vị với Raspberry Pi và Arduino - Cảnh báo cháy qua email

Mô tả dự án: 

Ở nhà nhiều roài, Tới giờ đi học à nha! Nhưng mà lỡ đang đi học mà nhà có chuyện gì (cháy nhà) thì sao? Cùng bắt tay vào làm hệ thống cảnh báo cháy qua email với tui nha!

Nguyên lý

Các bạn ở cộng đồng Arduino Việt Nam thì quá quen với việc đo nhiệt độ rồi đúng hem? Nhưng mà đo xong để làm gì? Một ứng dụng đơn giản là nếu trên 60 độ thì chắc là có chuyện không lành rồi. Cách kiểm tra chắc ăn nhất là chạy dzìa coi, nhưng mà đây là thời buổi IoT rồi. Với Raspberry thì việc đơn giản hơn nhiều: tự nó sẽ đọc nhiệt độ Arduino khai báo qua cổng Serial và gửi hình ảnh qua email cho bạn nếu nhiệt độ trên 60. Đây là gợi ý ứng dụng kết hợp giữa Pi và Arduino. Ai kiu 2 bạn này là nước với lửa nào?. Thay vì mua thêm Ethernet shield đắt tiền, tại sao không mua Pizero, giá thành rẻ hơn mà lại nhiều chức năng hơn với Python. 

Chuẩn bị

 

  • 1 Raspberry Pi hay Pizero
  • Raspberry Pi Camera Module
  • 1 Arduino 
  • 1 cảm biến DS18B20
  • Điện trở 4.7kOhm

Bạn nối theo như bài đã viết trên diễn đàn nha:http://arduino.vn/bai-viet/977-huong-dan-su-dung-cam-bien-nhiet-do-ds18b20-55degc-den-125degc-sai-so-05degc

 

Sau đó nối Arduino với USB của Raspberry Pi là xong.

    Code Arduino

    Đây là code thầy tui đưa. Có sao ghi dzậy

    #include <OneWire.h>
    
    // OneWire DS18S20, DS18B20, DS1822 Temperature Example
    //
    // http://www.pjrc.com/teensy/td_libs_OneWire.html
    //
    // The DallasTemperature library can do all this work for you!
    // http://milesburton.com/Dallas_Temperature_Control_Library
    
    OneWire  ds(2);  // on pin 2CM0'CO (a 4.7K resistor is necessary)
    
    void setup(void) {
      Serial.begin(9600);
    }
    
    void loop(void) {
      byte i;
      byte present = 0;
      byte type_s;
      byte data[12];
      byte addr[8];
      float celsius;
      
      if ( !ds.search(addr)) {
        Serial.println("No more addresses.");
        Serial.println();
        ds.reset_search();
        delay(250);
        return;
      }
      
      Serial.print("ROM =");
      for( i = 0; i < 8; i++) {
        Serial.write(' ');
        Serial.print(addr[i], HEX);
      }
    
      if (OneWire::crc8(addr, 7) != addr[7]) {
          Serial.println("CRC is not valid!");
          return;
      }
      Serial.println();
     
      // the first ROM byte indicates which chip
      switch (addr[0]) {
        case 0x10:
          Serial.println("Chip = DS18S20");  // or old DS1820
          type_s = 1;
          break;
        case 0x28:
          Serial.println("Chip = DS18B20");
          type_s = 0;
          break;
        case 0x22:
          Serial.println("Chip = DS1822");
          type_s = 0;
          break;
        default:
          Serial.println("Device is not a DS18x20 family device.");
          return;
      } 
    
      ds.reset();
      ds.select(addr);
      ds.write(0x44, 1);        // start conversion, with parasite power on at the end
      
      delay(1000);     // maybe 750ms is enough, maybe not
      // we might do a ds.depower() here, but the reset will take care of it.
      
      present = ds.reset();
      ds.select(addr);    
      ds.write(0xBE);         // Read Scratchpad
    
      Serial.print("Data = ");
      Serial.print(present, HEX);
      Serial.print(" ");
      for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
        Serial.print(data[i], HEX);
        Serial.print(" ");
      }
      Serial.print("CRC=");
      Serial.print(OneWire::crc8(data, 8), HEX);
      Serial.println();
    
      // Convert the data to actual temperature
      // because the result is a 16 bit signed integer, it should
      // be stored to an "int16_t" type, which is always 16 bits
      // even when compiled on a 32 bit processor.
      int16_t raw = (data[1] << 8) | data[0];
      if (type_s) {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10) {
          // "count remain" gives full 12 bit resolution
          raw = (raw & 0xFFF0) + 12 - data[6];
        }
      } else {
        byte cfg = (data[4] & 0x60);
        
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
        
        //// default is 12 bit resolution, 750 ms conversion time
      }
      celsius = (float)raw / 16.0;
      
      Serial.print("Temperature = ");
      Serial.print(celsius);
      Serial.print(" Celsius, ");
    }

    Code trên Raspberry pi

    Chép đoạn code sau và lưu lại với tên di_hoc_thoi.py. 
     
    #!/usr/bin/bash
    #By MonsieurVechai
    import time
    import webbrowser
    import os, subprocess
    import re, serial
    
    import smtplib
    from email import Encoders
    from email.MIMEMultipart import MIMEMultipart
    from email.MIMEBase import MIMEBase
    from email.MIMEText import MIMEText
    
    
    '''
    serial stuff returned:
        ROM = 22 D 8D 16 0 0 0 C9
        4B 46 7F FF 2 10 71  CRC=71
          Temperature = 22.87 Celsius, 73.18 Fahrenheit
          No more addresses.
    '''
    
    
    class ds18x20:
        def __init__(self):
            try:
                self.ser = serial.Serial('COM1', 9600, timeout=1)
            except:
                print "Cannot open serial port"
                exit(1)
            print "ds18x20 device serial link opened"    
            self.ser.flushInput()
    
        def readTemperature(self):
            isTemp = False
            while isTemp == False:
                line = self.ser.readline()
                if line.startswith("Temperature"):
                    isTemp = True
                    re_list = re.findall('\d+.\d+',line) # find the decimal numbers in the string and put to list using re (regular expression)
                    temperature = float(re_list[0])
            return temperature
    
    def close(self):
            self.ser.close()
            print 'Device closed'
    
    
    def send_mail(file, temperature):    
        UserName = "somethingd@gmail.com"
        Password = "something"
        Recipient = "something"
        
        msg = MIMEMultipart()
        msg['From'] = UserName
        msg['To'] = Recipient
        msg['Subject'] = "High temperature detected on " + datetime.now().strftime("%Y_%m_%d_%H_%M_%S.h264") 
        text = "The house may be burning now. Temperature is: " + str(temperature)
        msg.attach( MIMEText(text) ) 
        
        part = MIMEBase("application", "octet-stream")
        fo=open(file,"rb")
        part.set_payload(fo.read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"'  %os.path.basename(file))
        msg.attach(part)
    
        s = smtplib.SMTP('smtp.gmail.com:587')
        s.ehlo()
        s.starttls()
        s.login(UserName, Password)
        s.sendmail(UserName, Recipient, msg.as_string())
        s.close()
    
    
    def read_temperature():
        dev = ds18x20()
        #Sometimes IndexError happens and we need to take the temperature measurement again
        try:
         temp = dev.readTemperature()
        except IndexError:
         temp = dev.readTemperature()
    
        dev.close() #Have to close device after use
        return float(temp)
    
    
    def main(): 
        dev = ds18x20()  
        print "Arduino is ready."
        
        camera = PiCamera()
        print "Pi Camera is ready."
    
        try:       
            # Loop until users quit with CTRL-C
            while True :  
                # Read Temperature from Arduino
                temperature = read_temperature()
                print "Current Temperature: " + str(temperature)
                if temperature > 60:
                    print "High temperature detected. Start recording movie."
                    filename = datetime.now().strftime("%Y_%m_%d_%H_%M_%S.h264")
                    camera.start_recording(filename)
                    time.sleep(20)
                    camera.stop_recording()
                    path_of_movie = os.path.abspath(filename)
                       
                    #Sending email
                    try:
                        send_mail(path_of_movie, temperature)
                        print "Sending email done. Ready to read new temperature."
                    except IOError:
                        print "Something wrong. Mail not sent."
                    time.sleep(0.01)
        
        except KeyboardInterrupt:
            print "Quit program"
            
            
    if __name__ == "__main__":
        main()

     

    Chỉnh sửa trên code Python

    Thay đổi địa chỉ email bằng địa chỉ email và password của bạn (phải là Gmail (cho dễ) nhé). Nhớ là phải để trong ngoặc kép nha:

     

    Tìm cổng serial của Arduino bằng cách nhập lệnh:

    • cd /dev

    Rút Arduino ra và gõ ls, bạn sẽ thấy bảng sau:

     Cắm Arduino vào và tiếp tục gõ ls, bạn sẽ thấy có cổng khác xuất hiện. Giả sử đó là COM2. Thay thế COM2 trong ô đỏ sau của Python code:

     

     

    Lưu code lại. Mở terminal trong thư mục bạn lưu file python và nhập lệnh:

    python di_hoc_thoi.py

     

     

    Lưu ý

    • Code này chỉ hoạt động được trên tài khoản gmail thôi nha! Và bạn phải vào https://www.google.com/settings/secu..., chọn "Turn on" cho phần "Access for less secure apps" thì mới gửi mail bằng Python được.
    • Bạn nên tạo 1 tài khoản gmail email riêng vì bất cứ ai mở file python đều có thể đọc được mật khẩu hộp thư cá nhân của bạn.
    • Lần đầu làm bạn nên comment # cho đoạn send_mail(path_of_movie) để tránh tài khoảng bị khóa hộp thư vì bị hiểu nhầm là spam.
    • Bạn có thể chỉnh sửa thời gian quay ở đây, nhưng mà quay ít ít thoai, nặng quá là không gửi qua email được đâu (max 20MB):
    1. camera.start_recording(filename)
    2. time.sleep(20)

    Gợi ý nâng cao

    • Kết hợp với các cảm biến khác như khí gas, nước
    • Kết hợp với module SIM để gọi điện thoại

    Bài tới tui sẽ hướng dẫn dùng camera để quay time-lapse khi các bạn đang ở trường và email hình mỗi 15 phút.

    lên
    19 thành viên đã đánh giá bài viết này hữu ích.
    Từ khóa: 
    Các dự án được truyền cảm hứng

    Select any filter and click on Apply to see results

    Các bài viết cùng tác giả

    "Fiat Lux - Hãy có ánh sáng": (Phần 2) Viết code BLINK thần thánh cho neopixel WS2812

    Đây là phần 2 cho tutorial hướng dẫn cách lập trình LED 3 màu neopixel WS2812. Vì mỗi module LED là 1 mạch IC nên cách sử dụng hơi rắc rối hơn so với LED thông thường. Các bạn chú ý nha!

    lên
    22 thành viên đã đánh giá bài viết này hữu ích.

    Pi Zero W có gì lạ hơm em?

    Như các bạn đã biết, Pi Zero W được lên kệ vào sinh nhật của Raspberry Pi cách đây vài ngày. Và như thường lệ, hiện nay PZW đã cháy hàng trong vòng chưa đầy 1 tuần, mặc dù có giá gấp đôi so với phiên bản "2 tô phở" của người tiền nhiệm. Ta hãy cùng xem sự khác biệt ra sao nha!

    lên
    12 thành viên đã đánh giá bài viết này hữu ích.
    Từ khóa: