天氣實時顯示系統--基於python網絡爬蟲的樹莓派與Arduino藍牙通信

綜述


由樹莓派作爲上位機,定時運行python爬蟲程序,將結果通過藍牙發送給Arduino,Arduino接收到數據,將數據顯示在1602LCD屏上,如果數據中顯示會下雨,則亮起紅色LED以提醒並(拓展:使用SIM900GSM模塊,通過Arduino發信息給手機實時提醒。)

電子器件:

  1. raspberry pi 3B
  2. Arduino Uno
  3. HC-05藍牙主從一體模塊
  4. 1602LCD顯示屏
  5. HC-SR04超聲波測距模塊
  6. 9V電池
  7. 1000Ω電阻
  8. 紅色,綠色LED
  9. SIM900 GSM模塊(拓展)

樹莓派上位機

一:藍牙配置
目前知道有2種方法:
A:完全通過linux命令行完成

在Python環境下使用“import bluetooth”如果報出錯誤信息“ImportError: No module named bluetooth”則說明沒有安裝相應的包,執行一下命令安裝。

$sudo apt-get update
$sudo apt-get install bluetooth  bluez  python-bluez

進入藍牙連接工具

$ bluetoothctl
[NEW] Controller B8:27:EB:D3:61:B0 raspberrypi [default]
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful

開始掃描周圍藍牙設備

[bluetooth]# scan on 
Discovery started
[CHG] Controller B8:27:EB:D3:61:B0 Discovering: yes
[NEW] Device 98:14:01:10:C5:32 HC-05

連接藍牙設備

[bluetooth]# pair 98:14:01:10:C5:32 
Attempting to pair with 98:14:01:10:C5:32 
[CHG] Device 98:14:01:10:C5:32 Connected: yes
Connected: yes
Request PIN code
[agent] Enter PIN code: 1234
[CHG] Device 98:14:01:10:C5:32 UUIDs:
        00001101-0000-1000-8000-00805f9b34fb
[CHG] Device 98:14:01:10:C5:32 Paired: yes
Pairing successful

生成rfcomm0 文件(要用)

$ sudo rfcomm bind 0 98:14:01:10:C5:32

連接藍牙設備後,會在樹莓派的【/dev】目錄中創建一個藍牙設備的虛擬文件 /dev/rfcomm0

如果大家覺得這方法繁瑣且難以記住,還有一種相對簡答方法:

B:先通過桌面,再通過命令行
較新的樹莓派桌面支持顯示藍牙設備,我們可以通過桌面操作連接藍牙
升級安裝藍牙相關軟件包
關鍵第三步用來更新桌面環境,我的桌面版本老,故要執行

$sudo apt-get update 
$sudo apt-get upgrade -y 
$sudo apt-get dist-upgrade -y 
$sudo apt-get install pi-bluetooth bluez bluez-firmware blueman

找到桌面藍牙圖標
這裏寫圖片描述

之後的操作和命令行一樣:
先進入bluetoothctl

$ bluetoothctl

找到對應的藍牙地址(這是會自動顯示再桌面下已連接的藍牙設備)
再退出

exit

最後生成rfcomm0 文件(要用)

$ sudo rfcomm bind 0 98:14:01:10:C5:32

二: python網絡爬蟲獲取天氣預報
首先導入python相應模塊

INDEX:
Requests 是用Python語言編寫,基於 urllib,採用 Apache2 Licensed 開源協議的 HTTP 庫。它比 urllib 更加方便,可以節約我們大量的工作,完全滿足 HTTP 測試需求。Requests 的哲學是以 PEP 20 的習語爲中心開發的,所以它比 urllib 更加 Pythoner。更重要的一點是它支持 Python3

Beautiful Soup提供一些簡單的、python式的函數用來處理導航、搜索、修改分析樹等功能。它是一個工具箱,通過解析文檔爲用戶提供需要抓取的數據,因爲簡單,所以不需要多少代碼就可以寫出一個完整的應用程序。
Beautiful Soup自動將輸入文檔轉換爲Unicode編碼,輸出文檔轉換爲utf-8編碼。你不需要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時,Beautiful Soup就不能自動識別編碼方式了。然後,你僅僅需要說明一下原始編碼方式就可以了。
Beautiful Soup已成爲和lxml、html6lib一樣出色的python解釋器,爲用戶靈活地提供不同的解析策略或強勁的速度。

serial 用於讀串口的數據,使用非常的方便

time 處理與時間有關的操作,包括程序中斷等

import requests
from bs4 import BeautifulSoup
import serial
from time import sleep#程序中斷執行函數

如果導入出現困難,用linux命令行進行下載更新
法1:

$sudo apt-get install python-requests

法2:(前提是已經下載python pip 模塊)

$sudo pip install python-requests

獲得各城市天氣預報網站函數

def get_url(city_name):#輸入參數爲城市名
    url = 'http://www.weather.com.cn/weather/'
    #打開存儲對應城市對應網址地址的txt文檔
    with open('city.txt', 'r', encoding='UTF-8') as fs:
        lines = fs.readlines()
        #對文件讀取遍歷
        for line in lines:
            if(city_name in line):#發現城市名
                code = line.split('=')[0].strip()#取得相應數字
                return url + code + '.shtml'#加到網址地址後
    raise ValueError('invalid city name')#未找到該城市

同路徑下有個存儲對應城市具體地址的txt文檔
格式:
101010100=北京
101010200=海淀

網絡爬蟲獲取地址中的內容
用簡單的 requests 配合 BeautifulSoup 獲取預報信息並保存。
下面兩步根據鏈接地址把網頁內容抓下來,然後進行解析,得到要保存的數據,返回的 content 是一個列表,每個元素是要保存的一行內容。

def get_content(url, data=None):
    rep = requests.get(url)
    rep.encoding = 'utf-8'
    return rep.text

def get_data(htmltext, city):
    content = []
    bs = BeautifulSoup(htmltext, "html.parser")
    body = bs.body
    data = body.find('div', {'id': '7d'})
    ul = data.find('ul')
    li = ul.find_all('li')
    for day in li:
        line = [city]
        date = day.find('h1').string
        line.append(date)
        text = day.find_all('p')
        line.append(text[0].string)
        if text[1].find('span') is None:
            temperature_H = None
        else:
            temperature_H = text[1].find('span').string.replace('℃', '')
        temperature_L = text[1].find('i').string.replace('℃', '')
        line.append(temperature_H)
        line.append(temperature_L)
        content.append(line)
    return content

對所獲得信息進行處理

def finds(strings):#中文字符串
#找相應中文
    a=strings.find("雨",0)
    b=strings.find("雲",0)
    c=strings.find("晴",0)
    if a!=-1:
        return 'r'#有雨發送‘r’
    if b!=-1:
        return 'c'#有云發送‘c’
    if c!=-1:
        return 's'#有陽發送‘s’

    #對沒有天氣情況的返回爲‘N’,result列表儲存今明2天天氣情況
if result[0][3]==None:
    result[0][3]='N'
if result[0][4]==None:
    result[0][4]='N'
if result[1][3]==None:
    result[1][3]= 'N'
if result[1][4]==None:
    result[1][3]='N'        

三: 與Arduino下位機通信

 #藍牙串口虛擬文件
 port='/dev/rfcomm0'
 serial=serial.Serial(port,9600)#設置藍牙波特率

for i in range(1,10):#多次發送保證發送成功
            #調用serial.write()其在python3中只能一位一位發送,故將數據轉爲按位發送
                serial.write(bytes(finds(result[0][2]),'UTF-8'))
                #發送空格,分開各數據
                serial.write(bytes(' ','UTF-8'))
                serial.write(bytes(result[0][3],'UTF-8'))
                serial.write(bytes(' ','UTF-8'))
                serial.write(bytes(result[0][4],'UTF-8'))
                serial.write(bytes(' ','UTF-8'))
                serial.write(bytes(finds(result[1][2]),'UTF-8'))
                serial.write(bytes(' ','UTF-8'))
                serial.write(bytes(result[1][3],'UTF-8'))
                serial.write(bytes(' ','UTF-8'))
                serial.write(bytes(result[1][4],'UTF-8'))
                serial.write(bytes(' ','UTF-8'))
                serial.flushInput()#清除串口緩衝區
                sleep(.8)#程序終止運行0.8s,太快CPU費勁,程序也容易卡,LCD也會有反應不過來,更新過快

Arduino 下位機:

一: 獲得樹莓派數據
在arduino中藍牙與串口使用方法相同

void got ()
  //收到藍牙信號   
{if (Serial.available())
     //不停讀取發送的一個個位,最多會有16位數據
  {for (int i=0;i<16;i++)
   {
     a=Serial.read();
     //將數據給數組
     b[i]=a;
     if (b[i]=='s')
//如果接收到要下雨信息,pin8至高電平,點亮紅色LED提醒
     {digitalWrite(9,HIGH);
     }
     if (b[i]=='r')
    //如果接收到要天晴信息,pin9至高電平,點亮綠色LED
     {digitalWrite(8,HIGH);
    }    

二:在LCD上顯示
要導入”LiquidCrystal”庫
這樣2行便解決

# include <LiquidCrystal.h>
 //設置光標位置   
lcd.setCursor(i,2);
 //寫入字符串
lcd.print(b[i]);       

三:數據更新
有2種不同的選擇:
A:通過超聲波傳感器接收距離信息,如果距離小於某值,則說明有人來了,向樹莓派發送信息,樹莓派進行數據更新
獲得距離

//超聲波傳感器輸出端       
# define 6 trig
 //超聲波傳感器輸入端 
# define 6 trig

float cm;//存儲探測距離
float temp;//存儲高脈衝信號長度

void distance ()
{digitalWrite(trig,LOW);
 delayMicroseconds(2);
 digitalWrite(trig,HIGH);//給一個10us秒的高脈衝,激發傳感器
 delayMicroseconds(10);
 digitalWrite(trig,LOW);

 temp=float(pulseIn(echo,HIGH));//檢測計算傳感器發出後接受到的高脈衝時長,其正比於距離
 cm=temp*17/1000;//公式換算}
}

循環loop函數中進行檢測更新發數據給樹莓派

void loop()
{ distance();//獲得距離
  if(cm<50)
  {Serial.write(int(cm));//發送信息給樹莓派
  for (int i=0;i<11;i++)
   {got();//多次獲得數據,保證數據正確完整
   lcd.setCursor(1,0);
   lcd.print("today tomorrow");//寫明今明兩天
   delay(800);}}//延時與樹莓派相匹配                      
}       

B:使用程序中斷定時進行:
這也有2種方法:
a:使用python time 模塊的sleep函數,執行中斷一段時間,之後繼續執行
例如我們讓每3小時更新一下,只要加上”sleep(60*60*3)”並稍微改動即可

b:使用linux下的crontab工具,設置程序定時執行
打開在pi用戶下的crontab

$sudo crontab -u pi -e

寫下

7 0 * * * python weather2.py
11 0 * * * python weather2.py
16 0 * * * python weather2.py

20 0 * * * python weather2.py

其格式是:
hour minute day month year command
退出vim編輯器後,很重要的一點是一定要執行如下命令,否則無法執行

$sudo /etc/init.d/cron restart  

則python程序將在7,11,16,20點執行
四:電路連接
不想用Fritzing畫圖了,直接寫了
1.LCD-Arduino這裏寫圖片描述
將電位器換成1000Ω電阻,另一端接地
2.HC-SR04
trig-6
echo-7

3.HC-05
TX-RX
RX-TX

4.LED
紅+-pin8
綠+-pin9
5.電源
考慮到盒子小體積,我使用了較小的9V電池,分別直接接IO口的VIN與GND,沒有接電源接口,主要是縮小體積。

五:拓展短信通知(沒錢買模塊啊!樹莓派一買就要吃土了!!還有關鍵Uno上只有一個RX,TX,得換arduino mega)
加個函數再調用就行

void sendSms(String phonecode ,String content) 
  {//電話號碼 ,短信內容 
  Serial3.println("AT+CMGS=\""+phonecode+"\"");
  delay(500);//必須延時,不加延時可以自己看結果
  Serial3.print(content);//短內容爲content;
  //不知爲什麼加這個?
  Serial3.write(0x1A)
  }

總體包裝:

先是用杜邦線連接調試,然後花了一個下午多把電路焊在洞洞板上(佈線自己還算滿意,學長或許就不這麼認爲了…),然後偶然看到實驗室的一個盒子大小剛好適合,便順便把盒子改造了下,把他塞進去了,還不錯。時間比較緊,焊接製作各過程都沒拍照,關鍵是近期手機壞了,不能拍照!
最後給一張我用老手機拍的模糊的最終成品照:
這裏寫圖片描述

總結:

大一下學期學的較亂,黑白道(軟硬件)通吃,卻都很不精,感覺有點不踏實,不過想想以後又不是靠這些吃飯(至少不大可能),覺得現在多瞭解些挺好,打好通識工科,爲以後打基礎吧,這學期從最初的stm32,到python與opencv圖形處理,再到樹莓派與linux,計劃之後再學學電路基礎,偏點硬件。
PS:
該項目是實驗室二輪考覈的題目,在匆忙之中將其完成,應該包含了大部分我學習的內容,還是比較綜合的吧,可能偏簡答了,但覺得實驗室應該沒人做過這個,應該算是較新的領域了,
相對比較實用(這也是我選擇項目的主要考慮因素)。也是完成了,感覺滿滿的成就感 ,別人是難以體會的,一種自我價值實現與創造,按柏格森說法,就是”生命創造論”,—個人創造衝動與工具理性的結合而產生,或者說是二者之間的一種相互妥協,這或許是2者最好的歸宿。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章