Đ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

    Bộ điều khiển PID - ứng dụng phần 2 - xe dò line dùng thuật toán PID

    Tiép nối bài viết về xe dò line cảm ơn Đỗ Hữu Toàn đã viết hộ mình phần 4. hôm nay mình sẽ làm cho chiếc xe dò line đi mượt và có hồn hơn 

    lên
    34 thành viên đã đánh giá bài viết này hữu ích.
    Các bài viết cùng tác giả

    Hot: Orange Pi Zero IoT đã ra lò!!!

    Vậy là Raspberry Pi Zero W đã được lên kệ hơn 1 tháng. Và đúng như dự đoán, các bạn Trung Quốc đã nhanh chóng cho ra đời 1 sản phẩm nhái đúng chất Tàu xì để cạnh tranh với Raspberry Pi Foundation. Chúng ta không lạ gì với các thể loại Pi cam, chuối, mận, trong đó Orange Pi có lẽ là sản phẩm Pi nhái ưa thích nhất ở VN với giá thành hợp túi tiền người tiêu dùng. Gần đây họ cho ra đời một sản phẩm mới có tên là Orange Pi Zero IoT với giá 10 Mỹ cành với hy vọng chiếm thị phần của Pi Zero W vốn dĩ luôn khan hàng. Ta hãy cùng xem sản phẩm này có gì đặc biệt nha! 

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

    Giới thiệu bo mạch 5 giao tiếp không giây đầu tiên trên thế giới | FiPy

    Bạn đang muốn thực hiện dự án Internet của Vạn Vật nhưng vẫn đang loay hoay chọn chuẩn giao tiếp không dây? Nên dùng bluetooth để tiết kiệm năng lượng? Nên dùng wifi để truy cập từ mọi nơi trên thế giới? Nên dùng GPRS để điều khiển khắp ở những nơi có sự hiện diện của ông chú Viettel? Nên dùng LoraWAN để truyền thông tin cách hàng chục km? Nên dùng Sigfox vừa xa vừa miễn phí? Bạn yêu thích ngôn ngữ Python đơn giản? Bài này tui sẽ giới thiệu về bo mạch sắp ra lò từ xứ sở hoa tulip xinh đẹp mang tên FiPy. Giá của bo là 33 eur nếu đặt trên Kickstarter và 40 eur nếu bạn mua sau khi dự án kết thúc.Bài viết thu thập thông tin từ Kickstarter.

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