前言:這篇是「威玲旺卡Aileen」和「阿狗A-Go」的原創(chuàng)物聯(lián)網(wǎng)邊造邊寫系列筆記。沒有告知時(shí)請不要轉(zhuǎn)載吶,謝謝。另外我要感謝Marcel Ochsendorf(馬賽)同學(xué)對我的指導(dǎo)森枪。
0. 本集問題情景:
阿狗想在何時(shí)何地都可以知道他生命中最重要的地方——狗窩的溫度和濕度。這樣他可以決定是不是需要打開暖氣和加濕器以保持他狗毛的蓬松和柔軟审孽,同時(shí)也可以知道供暖系統(tǒng)和加濕器的真正效果县袱。目前他能在一個網(wǎng)頁上看到實(shí)時(shí)數(shù)據(jù)就滿意了,阿狗對web框架一無所知瓷胧,手邊也只有一塊樹莓派显拳,他打算用很老很成熟的LAMP(Linux-Apache-MySQL-PHP)來實(shí)現(xiàn)它。
0. 這個邊造邊寫的筆記將會涵蓋:
- 部署一個aws虛擬主機(jī)搓萧,打造服務(wù)器+web構(gòu)架+域名
- 創(chuàng)建aws Linux AMI主機(jī)
- 通過yum安裝LAMP
- 為主機(jī)申請靜態(tài)IP杂数,修改域名DNS到主機(jī)
- 用樹莓派讀取溫度濕度傳感器數(shù)值并上傳數(shù)據(jù)庫(通過requests)
- 硬件連接DHT傳感器
- 安裝Adafruit Sensor Library,測試讀取傳感器數(shù)據(jù)
- 這里狗要思考一下在哪里登錄數(shù)據(jù)庫瘸洛,所以狗先去了第三部分揍移,然后回到這個點(diǎn)繼續(xù)
- 安裝requests,通過它進(jìn)行數(shù)據(jù)交流
- 創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu)反肋,用php與MySQL對話那伐,最終顯示傳感器實(shí)時(shí)數(shù)據(jù)至頁面
- 通過phpMyAdmin界面設(shè)計(jì)表結(jié)構(gòu)
- 寫用來登錄數(shù)據(jù)庫的db.php
- 寫用來執(zhí)行插入操作的insert.php(回到2.4,在樹莓派上requests它石蔗,測試數(shù)值是否插入數(shù)據(jù)庫成功)
- 寫顯示頁面
我們開始動手啦罕邀。
1. 部署一個aws虛擬主機(jī),打造服務(wù)器+web構(gòu)架+域名
1.1裝一個aws實(shí)例
按照非常好的官方文檔养距,
Amazon EC2 Linux 實(shí)例入門
新手教程-如何在 Amazon AWS 上搭建和部署網(wǎng)站
使用 SSH 連接到 Linux 實(shí)例
這一步的目標(biāo)是:
ssh鏈接實(shí)例成功!
我當(dāng)下的安全組設(shè)置诉探,感覺非常不安全,后面一定要改改棍厌。
說到要熟悉aws最快最好的方式肾胯,我不得不提qwiklabs,真實(shí)環(huán)境lab耘纱,非常棒敬肚。
1.2安裝Web構(gòu)架
教程走一個
教程:在 Amazon Linux 上安裝 LAMP Web 服務(wù)器
這一部的完成的鑒定是,登錄主機(jī)DNS可以看到它:
登錄主機(jī)DNS/phpinfo.php可以看到裝的php版本束析,
登錄主機(jī)DNS/phpMyAdmin可以看到數(shù)據(jù)庫登錄入口艳馒,
我安裝的過程中原來用
sudo yum install -y http php php-mysql mysql mysql-server
后來折騰了好久也弄不好phpMyAdmin,后來只能全卸載员寇,確定版本弄慰,這才搞定
sudo yum install -y httpd24 php70 mysql56-server php70-mysqlnd
創(chuàng)建index.php或者index.html就可以替換掉默認(rèn)主頁了。
這些都是在主機(jī)里弄的丁恭,沒有用到亞馬遜的RDS(Relational Database Service)也沒有掛載EFS(Elastic File System)留給之后探索曹动。
1.3為主機(jī)申請靜態(tài)IP,修改域名DNS到主機(jī)
官方文檔 彈性 IP 地址
獲得IP后一定要關(guān)聯(lián)運(yùn)行著的主機(jī)牲览,否則沒有關(guān)聯(lián)實(shí)例的IP會被扣費(fèi)墓陈,此外,如果申請了靜態(tài)IP并且關(guān)聯(lián)后第献,把主機(jī)給關(guān)掉了贡必,那么這個IP也會被扣費(fèi)。
阿狗買了一個叫wolfiethedog.de的域名庸毫,在DNS中將A地址指向靜態(tài)IP就完成了仔拟。但當(dāng)我用CNAME將www指向主機(jī)地IPv4地址(ec2-xxxxxxxx.eu-central-1.compute.amazonaws.com)卻一直失敗,現(xiàn)在也沒搞定飒赃,我把subdomain的“www”設(shè)置成域名跳轉(zhuǎn)到主頁作為臨時(shí)的辦法利花。
至此科侈,我們的aws+LAMP搞定了,用時(shí)沒超過2小時(shí)炒事。
2. 用樹莓派讀取溫度濕度傳感器數(shù)值并上傳數(shù)據(jù)庫(通過requests)
2.1 硬件連接DHT傳感器
樹莓派針腳的布局(派3至少是這樣的)
淘寶來的溫度濕度傳感器臀栈,一定要找找模塊名字,找到了叫DHT11挠乳,三個針腳VCC权薯,DATA和GND
分別接到01(3.3v電壓),07(GPIO04)和06(GOUND)
okay睡扬,希望成功吧盟蚣,啟動派,準(zhǔn)備讀取數(shù)值了卖怜。
2.2 安裝Adafruit Sensor Library屎开,測試讀取傳感器數(shù)據(jù)
我原來一直以為我需要讀出二進(jìn)制raw data再換算成可讀數(shù)據(jù),還琢磨著我該怎么查看它的輸出結(jié)構(gòu)呢韧涨?
但其實(shí)庫類已經(jīng)把這個問題給handle了牍戚。移步 https://github.com/adafruit/Adafruit_Python_DHT
安裝完之后,因?yàn)槲业膫鞲衅魇荄HT11虑粥,所以需要修改一下它的simpletest.py
import Adafruit_DHT
sensor = Adafruit_DHT.DHT11
pin = 4
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
成功啦如孝!
2.3 要思考一下在哪里登錄數(shù)據(jù)庫
我們差一點(diǎn)就要在樹莓派連接數(shù)據(jù)庫了,因?yàn)楫?dāng)時(shí)我一直在想用php連接數(shù)據(jù)庫該怎么碼娩贷,后來Marek說用python連接MySQL不就好了第晰,我那個時(shí)候思維被偏向了,我在派上安了MySQLdb彬祖,打算遠(yuǎn)程登錄數(shù)據(jù)庫茁瘦,然后再插入數(shù)據(jù),用root的身份和密碼竟然被拒絕储笑,這時(shí)我發(fā)現(xiàn)root是默認(rèn)沒有遠(yuǎn)程登錄權(quán)限的甜熔,我要通過mysql script去賦予權(quán)限,
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH PRIVILEGES;
隨后還經(jīng)歷了mysql需要升級突倍,卻一直失敗腔稀,最后要--force才通過
mysql_upgrade --force -uroot -p
直到都折騰完了,我才頓悟羽历,我為什么要在派上登錄呢焊虏?這情況派只要構(gòu)建一個 Request 對象,其他事情都該交給服務(wù)器秕磷。所以接下來我們要開始在服務(wù)器上寫php诵闭。
3. 創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu),用php與MySQL對話,最終顯示傳感器實(shí)時(shí)數(shù)據(jù)至頁面
3.1 通過phpMyAdmin界面設(shè)計(jì)表結(jié)構(gòu)
本科知識復(fù)習(xí)疏尿,建表瘟芝,我們在數(shù)據(jù)庫DHT下,建立了一個叫Pi_reader的表润歉,其中有鍵:
- ID索引(作為主鍵同時(shí)自動加A_I)
- 溫度
- 濕度
- 時(shí)間戳
Pi_reader表結(jié)構(gòu).png
期間還溫習(xí)了一下 char模狭、varchar和text的區(qū)別
3.2 寫用來登錄數(shù)據(jù)庫的db.php
Apache的web文件默認(rèn)地址是 /var/www/html
其實(shí)root根本不需要遠(yuǎn)程登錄權(quán)限颈抚。
db.php代碼
<?php
DEFINE('DB_USERNAME','root');
DEFINE('DB_PASSWORD','password');
DEFINE('DB_HOST','xx.xx.xxx.xxx');
DEFINE('DB_DATABASE','DHT');
$mysqli = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
if (mysqli_connect_error()){
die('Connect Error('.mysqli_connect_error().')'.mysqli_connect_error());
}
echo '<i>數(shù)據(jù)庫已成功連接踩衩。</i>';
?>
3.3 寫用來執(zhí)行插入操作的insert.php
我們需要將收到的請求,如果是合理的贩汉,就添加進(jìn)數(shù)據(jù)庫驱富。
合理是指符合這樣的格式
http://xx.xx.xxx.xxx.xxx/insert.php?temp=aa&hum=bb&token=0000
那么溫度aa,濕度bb和timestamp都會被加入到數(shù)據(jù)庫匹舞。
其中token是充當(dāng)一個密碼保護(hù)的功能褐鸥。
如果數(shù)據(jù)項(xiàng)目很多的話,可以傳輸一個xml或者json
insert.php代碼
<?php
include 'db.php';
if(!isset($_GET["token"]) || $_GET["token"] != "0000"){
echo "wrong_token";
exit();
}
$temp = $_GET["temp"];
$hum = $_GET["hum"];
echo $temp;
$sql = "INSERT INTO Pi_reader (id,temperature,humidity,timestamp) VALUES (NULL, '". $temp ."','". $hum ."', CURRENT_TIMESTAMP);";
$result = mysqli_query($mysqli, $sql);
?>
3.4 寫顯示頁面
在第一集中赐稽,我只寫了白板叫榕。
連接數(shù)據(jù)庫后,讀取一個表的所有記錄姊舵,循環(huán)輸出三個鍵值晰绎,溫度,濕度括丁,時(shí)間戳荞下。
index.php
<?php
echo "<h1>阿狗狗窩的溫度濕度實(shí)時(shí)監(jiān)視器</h1>";
include 'db.php';
$query = "SELECT * FROM Pi_reader";
$result = mysqli_query($mysqli, $query);
echo "<table>";
echo "<tr><td>" . "<b>溫度</b>" . "</td><td>" . "<b>濕度</b>" . "</td><td>". "<b>時(shí)間</b>". "</td></tr>";
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC))
{
echo "<tr><td>" . $row[temperature] . "°C </td><td>" . $row[humidity] . "% </td><td>". $row[timestamp]. "</td></tr>";
}
echo "</table>";
mysql_close();
?>
2.4 回到樹莓派,完成最后的對服務(wù)器的請求
現(xiàn)在只剩下最后一步了史飞,在派每次讀取數(shù)據(jù)后尖昏,我們想要它發(fā)送一個請求到服務(wù)器,這個請求說构资,“我請求把xx溫度xx濕度加入數(shù)據(jù)庫抽诉。”
而且我們希望1分鐘可以更新一次數(shù)據(jù)吐绵。
我們安裝了 Requests
直接在剛才讀取數(shù)據(jù)的腳本上粗暴地改動:
#!/usr/bin/python
import Adafruit_DHT
import requests
import time
sensor = Adafruit_DHT.DHT11
pin = 4
#humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
temp_temp = 0
temp_hum = 0
while(1):
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
if str(humidity) is not str(temp_hum) or str(temperature) is not str(temp_temp):
r = requests.get("http://xx.xx.xxx.xxx/insert.php?token=0000&temp="+ str(temperature) +"&hum=" +str( humidity))
print(r.status_code)
print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temperature, humidity))
temp_temp = temperature
temp_hum = humidity
else:
print('Failed to get reading. Try again!')
time.sleep(60)
測試迹淌!
好,我們現(xiàn)在登錄 http://wolfiethedog.de/woofaniot/s01e01/ 看看效果
頁面出現(xiàn)了樹莓派中獲取的當(dāng)下溫度和濕度拦赠,細(xì)細(xì)研究巍沙,時(shí)間間距并不是準(zhǔn)時(shí)的1分鐘。request給服務(wù)器的過程中還是出現(xiàn)了些短小的延時(shí)的荷鼠。
沒有css的html終究是難看的句携,但是我們的毛坯房已經(jīng)有了。下一集我和阿狗會專門研究顯示的儀表盤允乐,dashboard矮嫉。
這個實(shí)驗(yàn)的額外收獲就是削咆,那個小小的加濕器在整個房間的效果上還是有功效的。
至此蠢笋,《嚎出一個極簡物聯(lián)網(wǎng)》第一集《美味的云端LAMP派》就完成了拨齐。
耶!